From 3b13d9a2a367db84d48940460532c17a374bb488 Mon Sep 17 00:00:00 2001 From: schererleander Date: Thu, 5 Feb 2026 12:03:07 +0100 Subject: feat(modules): use dendritic pattern --- modules/services/dns.nix | 34 +++++++++++ modules/services/gpg.nix | 17 ++++++ modules/services/nextcloud.nix | 131 +++++++++++++++++++++++++++++++++++++++++ modules/services/nginx.nix | 27 +++++++++ modules/services/openssh.nix | 35 +++++++++++ modules/services/site.nix | 20 +++++++ modules/services/sunshine.nix | 13 ++++ 7 files changed, 277 insertions(+) create mode 100644 modules/services/dns.nix create mode 100644 modules/services/gpg.nix create mode 100644 modules/services/nextcloud.nix create mode 100644 modules/services/nginx.nix create mode 100644 modules/services/openssh.nix create mode 100644 modules/services/site.nix create mode 100644 modules/services/sunshine.nix (limited to 'modules/services') diff --git a/modules/services/dns.nix b/modules/services/dns.nix new file mode 100644 index 0000000..1917bf0 --- /dev/null +++ b/modules/services/dns.nix @@ -0,0 +1,34 @@ +{ + flake.modules.nixos.dns = + { lib, ... }: + let + servers = [ + "1.1.1.1#cloudflare-dns.com" + "1.0.0.1#cloudflare-dns.com" + "9.9.9.9#dns.quad9.net" + "149.112.112.112#dns.quad9.net" + ]; + fallbackServers = [ + "8.8.8.8#dns.google" + "8.8.4.4#dns.google" + ]; + in + { + services.resolved = { + enable = true; + settings = { + Resolve = { + DNS = servers; + FallbackDNS = fallbackServers; + DNSSEC = true; + DNSOverTLS = true; + Domains = [ "~." ]; + }; + }; + }; + networking = { + nameservers = servers; + networkmanager.dns = lib.mkDefault "systemd-resolved"; + }; + }; +} diff --git a/modules/services/gpg.nix b/modules/services/gpg.nix new file mode 100644 index 0000000..6b1f2a8 --- /dev/null +++ b/modules/services/gpg.nix @@ -0,0 +1,17 @@ +{ + flake.modules.homeManager.gpg = + { + pkgs, + ... + }: + { + programs.gpg = { + enable = true; + }; + + services.gpg-agent = { + enable = true; + pinentry.package = if pkgs.stdenv.isDarwin then pkgs.pinentry_mac else pkgs.pinentry-curses; + }; + }; +} diff --git a/modules/services/nextcloud.nix b/modules/services/nextcloud.nix new file mode 100644 index 0000000..1c6e656 --- /dev/null +++ b/modules/services/nextcloud.nix @@ -0,0 +1,131 @@ +{ + flake.modules.nixos.nextcloud = + { + config, + lib, + pkgs, + ... + }: + { + services.nextcloud = { + enable = true; + package = pkgs.nextcloud32; + hostName = "cloud.schererleander.de"; + https = true; + database.createLocally = true; + maxUploadSize = "16G"; + config = { + dbtype = "mysql"; + adminuser = "schererleander"; + adminpassFile = config.sops.secrets."nextcloud-admin-pass".path; + }; + secrets = { + secret = config.sops.secrets."nextcloud-secret".path; + }; + settings = { + maintenance_window_start = 2; # 02:00 + default_phone_region = "de"; + overwriteProtocol = "https"; + trusted_domains = [ "cloud.schererleander.de" ]; + logtimezone = config.time.timeZone; + log_type = "file"; + # Disable mail functionality for single-user instance + mail_smtpmode = "null"; + }; + phpOptions."opcache.interned_strings_buffer" = "64"; + }; + + services.nginx.virtualHosts = { + "cloud.schererleander.de" = { + forceSSL = true; + sslCertificate = config.sops.secrets."cert_fullchain".path; + sslCertificateKey = config.sops.secrets."cert_private".path; + }; + }; + + services.borgbackup.jobs.nextcloud = { + paths = [ + "/var/lib/nextcloud" + "/var/lib/backup/nextcloud/db" + ]; + repo = "$BORG_REPO"; + encryption.mode = "none"; + user = "root"; + group = "root"; + environment = { + BORG_RSH = "ssh -i ${ + config.sops.secrets."borgbase_ssh_key".path + } -o StrictHostKeyChecking=accept-new"; + TMPDIR = "/var/tmp"; + }; + compression = "auto,lzma"; + startAt = "daily"; + readWritePaths = [ + "/var/lib/backup" + "/var/lib/nextcloud" + ]; + preHook = '' + set -euo pipefail + + export BORG_REPO="$(cat ${config.sops.secrets."borg_repo".path})" + + 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 = { + enable = true; + bantime = lib.mkDefault "1h"; + 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; + findtime = 43200; + }; + }; + }; + }; + + environment.etc = { + # 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":""%(_groupsre)s,?\s*"message":"Login failed: + ^\{%(_groupsre)s,?\s*"remoteAddr":""%(_groupsre)s,?\s*"message":"Trusted domain error. + datepattern = ,?\s*"time"\s*:\s*"%%Y-%%m-%%d[T ]%%H:%%M:%%S(%%z)?" + '' + ); + }; + }; +} diff --git a/modules/services/nginx.nix b/modules/services/nginx.nix new file mode 100644 index 0000000..6ad4c0f --- /dev/null +++ b/modules/services/nginx.nix @@ -0,0 +1,27 @@ +{ + flake.modules.nixos.nginx = + { ... }: + { + 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/services/openssh.nix b/modules/services/openssh.nix new file mode 100644 index 0000000..68d1511 --- /dev/null +++ b/modules/services/openssh.nix @@ -0,0 +1,35 @@ +{ + flake.modules.nixos.openssh = + { + lib, + ... + }: + { + services.openssh = { + enable = true; + ports = [ 8693 ]; + settings = { + PasswordAuthentication = false; + X11Forwarding = false; + PermitRootLogin = "yes"; + }; + }; + networking.firewall.allowedTCPPorts = [ 8693 ]; + + services.fail2ban = { + enable = true; + bantime = lib.mkDefault "1h"; + jails = { + sshd = { + enabled = true; + settings = { + port = 8693; + backend = "systemd"; + maxretry = 4; + findtime = "10m"; + }; + }; + }; + }; + }; +} diff --git a/modules/services/site.nix b/modules/services/site.nix new file mode 100644 index 0000000..d863dbc --- /dev/null +++ b/modules/services/site.nix @@ -0,0 +1,20 @@ +{ + flake.modules.nixos.site = + { + config, + inputs, + ... + }: + { + imports = [ + inputs.site.nixosModules.default + ]; + + services.site = { + enable = true; + domain = "schererleander.de"; + sslCertificate = config.sops.secrets."cert_fullchain".path; + sslCertificateKey = config.sops.secrets."cert_private".path; + }; + }; +} diff --git a/modules/services/sunshine.nix b/modules/services/sunshine.nix new file mode 100644 index 0000000..69496f2 --- /dev/null +++ b/modules/services/sunshine.nix @@ -0,0 +1,13 @@ +{ + flake.modules.nixos.sunshine = + { ... }: + { + services.sunshine = { + enable = true; + autoStart = true; + capSysAdmin = true; + openFirewall = true; + }; + hardware.graphics.enable = true; + }; +} -- cgit v1.3.1