{ lib, pkgs, ... }: let nasData = "/media/nas/main"; in { systemd = { network.wait-online.enable = false; services = { # Force tailscaled to use nftables (Critical for clean nftables-only systems) # This avoids the "iptables-compat" translation layer issues. tailscaled.serviceConfig.Environment = [ "TS_DEBUG_FIREWALL_MODE=nftables" ]; # Pre-create extensions and grant superuser-owned objects that the sparkyfitness # role cannot manage itself. Appended to postgresql-setup.service which already # runs as the postgres superuser after the DB is confirmed ready. # # 1. pg_stat_statements requires superuser to CREATE EXTENSION. # 2. The extension installs functions owned by the postgres superuser; the # sparkyfitness role cannot GRANT EXECUTE on objects it doesn't own, so we # pre-grant them here before the app's grantPermissions() runs. postgresql-setup.script = lib.mkAfter '' psql -d sparkyfitness -c " CREATE EXTENSION IF NOT EXISTS pg_stat_statements; GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO sparkyfitness; GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA pg_catalog TO sparkyfitness; " ''; }; }; networking.nftables.enable = true; boot.initrd.systemd.network.wait-online.enable = false; # Services configs services = { tailscale = { enable = true; openFirewall = true; useRoutingFeatures = "server"; extraUpFlags = [ "--advertise-exit-node" "--accept-dns=false" "--advertise-routes=10.0.1.0/24" "--hostname=jallen-nas" ]; extraSetFlags = [ "--advertise-exit-node" "--hostname=jallen-nas" "--webclient" ]; # authKeyFile = "/media/nas/main/nix-app-data/tailscale/auth"; }; postgresql = { enable = true; package = pkgs.postgresql_16; enableTCPIP = true; dataDir = "${nasData}/databases/postgresql"; ensureDatabases = [ "authentik" "homeassistant" "nextcloud" "onlyoffice" "synapse" "sparkyfitness" "suggestarr" ]; ensureUsers = [ { name = "authentik"; ensureDBOwnership = true; } { name = "homeassistant"; ensureDBOwnership = true; } { name = "nextcloud"; ensureDBOwnership = true; } { name = "onlyoffice"; ensureDBOwnership = true; } { name = "synapse"; ensureDBOwnership = true; } { name = "sparkyfitness"; ensureDBOwnership = true; } { name = "suggestarr"; ensureDBOwnership = true; } ]; # pg_hba.conf — use lib.mkForce to replace the module defaults entirely. # # Connection matrix: # postgres (admin) — Unix socket, peer (OS user postgres = DB user postgres) # authentik — Unix socket, peer (OS user authentik = DB user authentik) # nextcloud — Unix socket, peer (OS user nextcloud = DB user nextcloud) # onlyoffice — Unix socket, peer (OS user onlyoffice = DB user onlyoffice) [disabled] # synapse — Unix socket, peer via identMap (OS user matrix-synapse → DB user synapse) # homeassistant — TCP from nuc-nixos (10.0.1.4), scram-sha-256 # sparkyfitness — TCP from Podman bridge (10.88.0.0/16), scram-sha-256 authentication = lib.mkForce '' # TYPE DATABASE USER ADDRESS METHOD # All local Unix socket connections use peer auth (with identMap for mismatched names) local all all peer map=system # homeassistant runs on any host in the LAN. # trust is acceptable here: access is locked to a single known subnet on the LAN. host homeassistant homeassistant 10.0.1.0/24 trust # Podman container network — sparkyfitness server connects via host LAN IP host sparkyfitness sparkyfitness 10.88.0.0/16 scram-sha-256 # Podman container network — suggestarr server connects via host LAN IP host suggestarr suggestarr 10.88.0.0/16 scram-sha-256 ''; # identMap — maps OS usernames to PostgreSQL usernames for peer auth. # The catch-all regex rule allows any OS user whose name matches their DB user # directly (authentik, nextcloud, onlyoffice, postgres). # Explicit entries cover mismatched names. identMap = lib.mkForce '' # MAPNAME OS-USERNAME DB-USERNAME system matrix-synapse synapse system /^(.*)$ \1 ''; # TODO: set sparkyfitness password declaratively via ensureUsers.*.ensureClauses.password # once the SCRAM-SHA-256 hash is stored in SOPS (jallen-nas/sparky-fitness/db-password). # The old initialScript has been removed — it only ran on first DB init and is now stale. }; mysql = { enable = true; package = pkgs.mariadb; # explicit MariaDB package dataDir = "${nasData}/databases/mariadb"; settings.mysqld = { bind-address = "0.0.0.0"; port = 3306; }; initialDatabases = [ { name = "grimmory"; } ]; ensureUsers = [ { name = "grimmory"; ensurePermissions = { "database.*" = "ALL PRIVILEGES"; "*.*" = "SELECT, LOCK TABLES"; }; } ]; }; redis = { servers = { authentik = { enable = true; port = 6379; }; ccache = { enable = true; port = 6363; bind = "0.0.0.0"; openFirewall = true; extraParams = [ "--protected-mode no" ]; }; manyfold = { enable = true; port = 6380; }; onlyoffice = { enable = true; port = 6381; }; }; }; }; }