aboutsummaryrefslogtreecommitdiff
path: root/modules/nixos/server
diff options
context:
space:
mode:
authorschererleander <leander@schererleander.de>2026-01-09 16:57:15 +0100
committerschererleander <leander@schererleander.de>2026-01-09 23:13:49 +0100
commit3b5a73c436eb22e0cda59469263490705e149cb9 (patch)
treeae3f20ca6008b11f71247dfc6e2df8218de9b95c /modules/nixos/server
parentec45aae780da92e12cf82c5a32e336b14b7540ba (diff)
refactor: use flake-parts, change modules structure
Diffstat (limited to 'modules/nixos/server')
-rw-r--r--modules/nixos/server/fail2ban/default.nix25
-rw-r--r--modules/nixos/server/nextcloud/default.nix159
-rw-r--r--modules/nixos/server/nginx/default.nix54
-rw-r--r--modules/nixos/server/openssh/default.nix54
-rw-r--r--modules/nixos/server/site/default.nix28
5 files changed, 320 insertions, 0 deletions
diff --git a/modules/nixos/server/fail2ban/default.nix b/modules/nixos/server/fail2ban/default.nix
new file mode 100644
index 0000000..21020b5
--- /dev/null
+++ b/modules/nixos/server/fail2ban/default.nix
@@ -0,0 +1,25 @@
+{
+ config,
+ lib,
+ ...
+}:
+let
+ inherit (lib) mkEnableOption mkOption types mkIf;
+ cfg = config.nx.server.fail2ban;
+in
+{
+ options.nx.server.fail2ban = {
+ enable = mkEnableOption "fail2ban service";
+ bantime = mkOption {
+ description = "default bantime";
+ type = types.str;
+ default = "1h";
+ };
+ };
+ config = mkIf cfg.enable {
+ services.fail2ban = {
+ enable = true;
+ bantime = cfg.bantime;
+ };
+ };
+}
diff --git a/modules/nixos/server/nextcloud/default.nix b/modules/nixos/server/nextcloud/default.nix
new file mode 100644
index 0000000..7325c92
--- /dev/null
+++ b/modules/nixos/server/nextcloud/default.nix
@@ -0,0 +1,159 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+let
+ inherit (lib) mkEnableOption mkOption types mkIf;
+ cfg = config.nx.server.nextcloud;
+in
+{
+ options.nx.server.nextcloud = {
+ enable = mkEnableOption "Nextcloud server";
+ user = mkOption {
+ description = "System user for paths like SSH keys";
+ type = types.str;
+ };
+ adminUser = mkOption {
+ description = "Admin user";
+ type = types.str;
+ default = "schererleander";
+ };
+ adminPassFile = mkOption {
+ description = "Admin user key file";
+ type = types.str;
+ default = "/etc/nextcloud-admin-pass";
+ };
+ hostName = mkOption {
+ description = "Nextcloud hostname";
+ type = types.str;
+ default = "cloud.schererleander.de";
+ };
+ backup = mkOption {
+ description = "enable borgbase backups";
+ type = types.bool;
+ default = true;
+ };
+ backupSshKeyPath = mkOption {
+ description = "SSH key path for borgbase backup";
+ type = types.str;
+ default = "/home/${cfg.user}/.ssh/borgbase-nextcloud";
+ };
+ jail = mkOption {
+ description = "setup fail2ban jail";
+ type = types.bool;
+ default = config.nx.server.fail2ban.enable;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services.nextcloud = {
+ enable = true;
+ package = pkgs.nextcloud32;
+ hostName = cfg.hostName;
+ https = true;
+ database.createLocally = true;
+ maxUploadSize = "16G";
+ config = {
+ dbtype = "mysql";
+ adminuser = cfg.adminUser;
+ adminpassFile = cfg.adminPassFile;
+ };
+ settings = {
+ maintenance_window_start = 2; # 02:00
+ default_phone_region = "de";
+ overwriteProtocol = "https";
+ trusted_domains = [ cfg.hostName ];
+ logtimezone = config.time.timeZone;
+ log_type = "file";
+ };
+ phpOptions."opcache.interned_strings_buffer" = "64";
+ };
+
+ services.nginx.virtualHosts = mkIf ((config.nx.server.nginx or { }).enable or false) {
+ "${cfg.hostName}" = {
+ forceSSL = true;
+ sslCertificate = config.nx.server.nginx.sslCertificate;
+ sslCertificateKey = config.nx.server.nginx.sslCertificateKey;
+ };
+ };
+
+ services.borgbackup.jobs.nextcloud = mkIf cfg.backup {
+ paths = [
+ "/var/lib/nextcloud"
+ "/var/lib/backup/nextcloud/db"
+ ];
+ repo = "h8xn8qvo@h8xn8qvo.repo.borgbase.com:repo";
+ encryption.mode = "none";
+ environment = {
+ BORG_RSH = "ssh -i ${cfg.backupSshKeyPath} -o StrictHostKeyChecking=accept-new";
+ TMPDIR = "/var/tmp";
+ };
+ compression = "auto,lzma";
+ startAt = "daily";
+ readWritePaths = [
+ "/var/lib/backup"
+ "/var/lib/nextcloud"
+ ];
+ preHook = ''
+ set -euo pipefail
+ INSTALL="${pkgs.coreutils}/bin/install"
+ FIND="${pkgs.findutils}/bin/find"
+ MYSQLDUMP="${pkgs.mariadb.client}/bin/mariadb-dump"
+ GZIP="${pkgs.gzip}/bin/gzip"
+ OCC="${lib.getExe config.services.nextcloud.occ}"
+
+ # This command requires write access to /var/lib/backup.
+ $INSTALL -d -m 0750 -o root -g root /var/lib/backup/nextcloud/db
+
+ trap "$OCC maintenance:mode --off >/dev/null 2>&1 || true" EXIT
+
+ $OCC maintenance:mode --on
+
+ # Make a consistent database dump without locking the site.
+ $MYSQLDUMP --single-transaction --quick --lock-tables=false --databases nextcloud \
+ | $GZIP -c > /var/lib/backup/nextcloud/db/nextcloud-$(date +%F-%H%M%S).sql.gz
+
+ # Delete local dump files older than 14 days.
+ $FIND /var/lib/backup/nextcloud/db -type f -name "*.sql.gz" -mtime +14 -delete || true
+ '';
+ postHook = ''
+ set -euo pipefail
+ ${lib.getExe config.services.nextcloud.occ} maintenance:mode --off || true
+ '';
+ };
+
+ services.fail2ban = mkIf cfg.jail {
+ jails = {
+ nextcloud = {
+ enabled = true;
+ settings = {
+ backend = "systemd";
+ journalmatch = "SYSLOG_IDENTIFIER=Nextcloud";
+ # END modification to work with syslog instead of logile
+ port = 443;
+ protocol = "tcp";
+ filter = "nextcloud";
+ maxretry = 3;
+ bantime = 86400;
+ findtime = 43200;
+ };
+ };
+ };
+ };
+
+ environment.etc = mkIf cfg.jail {
+ # Adapted failregex for syslogs
+ "fail2ban/filter.d/nextcloud.local".text = pkgs.lib.mkDefault (
+ pkgs.lib.mkAfter ''
+ [Definition]
+ _groupsre = (?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*)
+ failregex = ^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Login failed:
+ ^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Trusted domain error.
+ datepattern = ,?\s*"time"\s*:\s*"%%Y-%%m-%%d[T ]%%H:%%M:%%S(%%z)?"
+ ''
+ );
+ };
+ };
+}
diff --git a/modules/nixos/server/nginx/default.nix b/modules/nixos/server/nginx/default.nix
new file mode 100644
index 0000000..2bdaba1
--- /dev/null
+++ b/modules/nixos/server/nginx/default.nix
@@ -0,0 +1,54 @@
+{
+ config,
+ lib,
+ ...
+}:
+let
+ inherit (lib) mkEnableOption mkOption types mkIf;
+ cfg = config.nx.server.nginx;
+in
+{
+ options.nx.server.nginx = {
+ enable = mkEnableOption "nginx reverse proxy" // {
+ default = true;
+ };
+ hostName = mkOption {
+ description = "url of server";
+ type = types.str;
+ default = "schererleander.de";
+ };
+ sslCertificate = mkOption {
+ description = "ssl certificate to use";
+ type = types.nullOr types.str;
+ default = "/etc/ssl/${cfg.hostName}/fullchain.pem";
+ };
+ sslCertificateKey = mkOption {
+ description = "ssl certificate key to use";
+ type = types.nullOr types.str;
+ default = "/etc/ssl/${cfg.hostName}/privkey.key";
+ };
+ };
+ config = mkIf cfg.enable {
+ services.nginx = {
+ enable = true;
+ recommendedGzipSettings = true;
+ recommendedOptimisation = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ appendHttpConfig = ''
+ map $scheme $hsts_header {
+ https "max-age=31536000; includeSubdomains; preload";
+ }
+ add_header Strict-Transport-Security $hsts_header;
+ #add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'self';" always;
+ add_header 'Referrer-Policy' 'same-origin';
+ add_header X-Frame-Options DENY;
+ add_header X-Content-Type-Options nosniff;
+ '';
+ };
+ networking.firewall.allowedTCPPorts = [
+ 80
+ 443
+ ];
+ };
+}
diff --git a/modules/nixos/server/openssh/default.nix b/modules/nixos/server/openssh/default.nix
new file mode 100644
index 0000000..675ceaf
--- /dev/null
+++ b/modules/nixos/server/openssh/default.nix
@@ -0,0 +1,54 @@
+{
+ config,
+ lib,
+ ...
+}:
+
+let
+ inherit (lib) mkEnableOption mkOption types mkIf;
+ cfg = config.nx.server.openssh;
+in
+{
+ options.nx.server.openssh = {
+ enable = mkEnableOption "OpenSSH server";
+ port = mkOption {
+ description = "Port for openssh";
+ type = types.port;
+ default = 8693;
+ };
+ allowedUsers = mkOption {
+ description = "Users allowed to SSH";
+ type = types.listOf types.str;
+ default = [ ];
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services.openssh = {
+ enable = true;
+ ports = [ cfg.port ];
+ settings = {
+ PasswordAuthentication = false;
+ AllowUsers = cfg.allowedUsers;
+ X11Forwarding = false;
+ PermitRootLogin = "yes";
+ };
+ };
+ networking.firewall.allowedTCPPorts = [ cfg.port ];
+
+ services.fail2ban = {
+ jails = {
+ sshd = {
+ enabled = true;
+ settings = {
+ port = 8693;
+ backend = "systemd";
+ maxretry = 4;
+ findtime = "10m";
+ bantime = "1h";
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/modules/nixos/server/site/default.nix b/modules/nixos/server/site/default.nix
new file mode 100644
index 0000000..be603c6
--- /dev/null
+++ b/modules/nixos/server/site/default.nix
@@ -0,0 +1,28 @@
+{
+ config,
+ lib,
+ inputs,
+ ...
+}:
+let
+ inherit (lib) mkEnableOption mkIf;
+ cfg = config.nx.server.site;
+in
+{
+ imports = [
+ inputs.site.nixosModules.default
+ ];
+
+ options.nx.server.site = {
+ enable = mkEnableOption "personal website";
+ };
+
+ config = mkIf cfg.enable {
+ services.site = {
+ enable = true;
+ domain = "schererleander.de";
+ sslCertificate = "/etc/ssl/schererleander.de/fullchain.pem";
+ sslCertificateKey = "/etc/ssl/schererleander.de/privkey.key";
+ };
+ };
+}