about summary refs log tree commit diff stats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--flake.lock73
-rw-r--r--flake.nix5
-rw-r--r--modules/by-name/an/anubis/module.nix94
-rw-r--r--modules/by-name/at/atuin-sync/module.nix12
-rw-r--r--modules/by-name/co/constants/module.nix4
-rw-r--r--modules/by-name/et/etesync/module.nix14
-rw-r--r--modules/by-name/gi/git-back/module.nix10
-rw-r--r--modules/by-name/ma/mail/module.nix4
-rw-r--r--modules/by-name/ma/matrix/module.nix10
-rw-r--r--modules/by-name/ne/nextcloud/module.nix8
-rw-r--r--modules/by-name/re/redlib/module.nix10
-rw-r--r--modules/by-name/ru/rust-motd/module.nix2
-rw-r--r--modules/by-name/sh/sharkey/module.nix19
-rw-r--r--modules/by-name/st/stalwart-mail/module.nix2
-rw-r--r--modules/by-name/st/stalwart-mail/settings.nix2
-rwxr-xr-xscripts/build.sh7
-rwxr-xr-xscripts/check.sh20
-rwxr-xr-xscripts/test.sh12
-rw-r--r--tests/by-name/at/atuin-sync/test.nix6
-rw-r--r--tests/by-name/ba/back/test.nix9
-rw-r--r--tests/by-name/gi/git-server/test.nix9
-rwxr-xr-xupdate.sh3
22 files changed, 216 insertions, 119 deletions
diff --git a/flake.lock b/flake.lock
index 8e09c5f..8f28118 100644
--- a/flake.lock
+++ b/flake.lock
@@ -12,11 +12,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1761656077,
-        "narHash": "sha256-lsNWuj4Z+pE7s0bd2OKicOFq9bK86JE0ZGeKJbNqb94=",
+        "lastModified": 1762618334,
+        "narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=",
         "owner": "ryantm",
         "repo": "agenix",
-        "rev": "9ba0d85de3eaa7afeab493fed622008b6e4924f5",
+        "rev": "fcdea223397448d35d9b31f798479227e80183f6",
         "type": "github"
       },
       "original": {
@@ -73,11 +73,11 @@
     },
     "crane": {
       "locked": {
-        "lastModified": 1760924934,
-        "narHash": "sha256-tuuqY5aU7cUkR71sO2TraVKK2boYrdW3gCSXUkF4i44=",
+        "lastModified": 1765739568,
+        "narHash": "sha256-gQYx35Of4UDKUjAYvmxjUEh/DdszYeTtT6MDin4loGE=",
         "owner": "ipetkov",
         "repo": "crane",
-        "rev": "c6b4d5308293d0d04fcfeee92705017537cad02f",
+        "rev": "67d2baff0f9f677af35db61b32b5df6863bcc075",
         "type": "github"
       },
       "original": {
@@ -121,11 +121,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1756719547,
-        "narHash": "sha256-N9gBKUmjwRKPxAafXEk1EGadfk2qDZPBQp4vXWPHINQ=",
+        "lastModified": 1762286984,
+        "narHash": "sha256-9I2H9x5We6Pl+DBYHjR1s3UT8wgwcpAH03kn9CqtdQc=",
         "owner": "serokell",
         "repo": "deploy-rs",
-        "rev": "125ae9e3ecf62fb2c0fd4f2d894eb971f1ecaed2",
+        "rev": "9c870f63e28ec1e83305f7f6cb73c941e699f74f",
         "type": "github"
       },
       "original": {
@@ -141,11 +141,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1761899396,
-        "narHash": "sha256-XOpKBp6HLzzMCbzW50TEuXN35zN5WGQREC7n34DcNMM=",
+        "lastModified": 1765794845,
+        "narHash": "sha256-YD5QWlGnusNbZCqR3pxG8tRxx9yUXayLZfAJRWspq2s=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "6f4cf5abbe318e4cd1e879506f6eeafd83f7b998",
+        "rev": "7194cfe5b7a3660726b0fe7296070eaef601cae9",
         "type": "github"
       },
       "original": {
@@ -157,11 +157,11 @@
     "flake-compat": {
       "flake": false,
       "locked": {
-        "lastModified": 1761588595,
-        "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=",
+        "lastModified": 1765121682,
+        "narHash": "sha256-4VBOP18BFeiPkyhy9o4ssBNQEvfvv1kXkasAYd0+rrA=",
         "owner": "edolstra",
         "repo": "flake-compat",
-        "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5",
+        "rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3",
         "type": "github"
       },
       "original": {
@@ -203,11 +203,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1742649964,
-        "narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
+        "lastModified": 1763319842,
+        "narHash": "sha256-YG19IyrTdnVn0l3DvcUYm85u3PaqBt6tI6VvolcuHnA=",
         "owner": "cachix",
         "repo": "git-hooks.nix",
-        "rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
+        "rev": "7275fa67fbbb75891c16d9dee7d88e58aea2d761",
         "type": "github"
       },
       "original": {
@@ -292,27 +292,27 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1761903212,
-        "narHash": "sha256-lSIrqFA4mnukm8IPTp8x4IYZ+/kXLv2tZsvT0yv9FZM=",
+        "lastModified": 1765984163,
+        "narHash": "sha256-RNFlX1Dj0DuvXkbwtglNKFxYxhwh20m/oUN0Le54UXY=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "7e82f02937587358bce377bef87359f44e0fa07b",
+        "rev": "e5c822e4a0e21274ec0b53bdb5c73ac3c470c263",
         "type": "github"
       },
       "original": {
         "owner": "NixOS",
-        "ref": "nixos-25.05-small",
+        "ref": "nixos-25.11-small",
         "repo": "nixpkgs",
         "type": "github"
       }
     },
     "nixpkgs-unstable": {
       "locked": {
-        "lastModified": 1761907660,
-        "narHash": "sha256-kJ8lIZsiPOmbkJypG+B5sReDXSD1KGu2VEPNqhRa/ew=",
+        "lastModified": 1765949210,
+        "narHash": "sha256-DKHDrCurTyA7np6pvXd9JMwweAvmJeJ5vWBwRsx9Zi4=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "2fb006b87f04c4d3bdf08cfdbc7fab9c13d94a15",
+        "rev": "c92a2155af41ff104cc97a805998eab8f8514ba9",
         "type": "github"
       },
       "original": {
@@ -348,11 +348,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1761878277,
-        "narHash": "sha256-6fCtyVdTzoQejwoextAu7dCLoy5fyD3WVh+Qm7t2Nhg=",
+        "lastModified": 1765939271,
+        "narHash": "sha256-7F/d+ZrTYyOxnBZcleQZjOOEWc1IMXR/CLLRLLsVtHo=",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "6604534e44090c917db714faa58d47861657690c",
+        "rev": "8028944c1339469124639da276d403d8ab7929a8",
         "type": "github"
       },
       "original": {
@@ -370,22 +370,19 @@
         "git-hooks": "git-hooks",
         "nixpkgs": [
           "nixpkgs-unstable"
-        ],
-        "nixpkgs-25_05": [
-          "nixpkgs"
         ]
       },
       "locked": {
-        "lastModified": 1755110674,
-        "narHash": "sha256-PigqTAGkdBYXVFWsJnqcirrLeFqRFN4PFigLA8FzxeI=",
+        "lastModified": 1764185122,
+        "narHash": "sha256-+HUOwSIFLoyett2cvRjuFIbhobpHallfP9J2cia1apo=",
         "owner": "simple-nixos-mailserver",
         "repo": "nixos-mailserver",
-        "rev": "f5936247dbdb8501221978562ab0b302dd75456c",
+        "rev": "a14fe3b293ec2720e5b7fc72ad136d22967e12ba",
         "type": "gitlab"
       },
       "original": {
         "owner": "simple-nixos-mailserver",
-        "ref": "nixos-25.05",
+        "ref": "nixos-25.11",
         "repo": "nixos-mailserver",
         "type": "gitlab"
       }
@@ -412,11 +409,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1761311587,
-        "narHash": "sha256-Msq86cR5SjozQGCnC6H8C+0cD4rnx91BPltZ9KK613Y=",
+        "lastModified": 1766000401,
+        "narHash": "sha256-+cqN4PJz9y0JQXfAK5J1drd0U05D5fcAGhzhfVrDlsI=",
         "owner": "numtide",
         "repo": "treefmt-nix",
-        "rev": "2eddae033e4e74bf581c2d1dfa101f9033dbd2dc",
+        "rev": "42d96e75aa56a3f70cab7e7dc4a32868db28e8fd",
         "type": "github"
       },
       "original": {
diff --git a/flake.nix b/flake.nix
index b67caa5..4c847b6 100644
--- a/flake.nix
+++ b/flake.nix
@@ -2,7 +2,7 @@
   description = "Nixos server config";
 
   inputs = {
-    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05-small";
+    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11-small";
     nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable-small";
 
     library.url = "git+https://git.foss-syndicate.org/vhack.eu/nix-library?ref=prime";
@@ -75,10 +75,9 @@
       inputs = {};
     };
     simple-nixos-mailserver = {
-      url = "gitlab:simple-nixos-mailserver/nixos-mailserver/nixos-25.05";
+      url = "gitlab:simple-nixos-mailserver/nixos-mailserver/nixos-25.11";
       inputs = {
         flake-compat.follows = "flake-compat";
-        nixpkgs-25_05.follows = "nixpkgs";
         nixpkgs.follows = "nixpkgs-unstable";
       };
     };
diff --git a/modules/by-name/an/anubis/module.nix b/modules/by-name/an/anubis/module.nix
new file mode 100644
index 0000000..4e70e4f
--- /dev/null
+++ b/modules/by-name/an/anubis/module.nix
@@ -0,0 +1,94 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.vhack.anubis;
+
+  anubisInstances =
+    lib.mapAttrs (domain: conf: {
+      settings = {
+        TARGET = conf.target;
+        BIND = "/run/anubis/anubis-${domain}/anubis.sock";
+        METRICS_BIND = "/run/anubis/anubis-${domain}/anubis-metrics.sock";
+      };
+    })
+    cfg.instances;
+
+  nginxVirtualHosts = lib.mapAttrs' (domain: conf:
+    lib.nameValuePair domain {
+      locations."/" = {
+        proxyPass = "http://unix:${config.services.anubis.instances."${domain}".settings.BIND}";
+
+        recommendedProxySettings = true;
+        proxyWebsockets = true;
+      };
+
+      enableACME = true;
+      forceSSL = true;
+    })
+  cfg.instances;
+in {
+  options.vhack.anubis.instances = lib.mkOption {
+    description = ''
+      Protect this reverse proxy with anubis.
+
+      The attr key is the subdomain, the value the config.
+    '';
+
+    type = lib.types.attrsOf (lib.types.submodule {
+      options = {
+        target = lib.mkOption {
+          description = "nginx `proxyPass` target";
+          type = lib.types.str;
+          example = "http://127.0.0.1:8080";
+        };
+      };
+      config = {};
+    });
+
+    default = {};
+
+    example = lib.literalExample ''
+      {
+        target = "http://127.0.0.1:$${toString config.servies.<name>.port}";
+      }
+    '';
+  };
+
+  config = {
+    users = {
+      users.nginx.extraGroups = [
+        config.services.anubis.defaultOptions.group
+      ];
+
+      users.anubis = {
+        uid = config.vhack.constants.ids.uids.anubis;
+        group = "anubis";
+      };
+      groups.anubis.gid = config.vhack.constants.ids.gids.anubis;
+    };
+
+    vhack.nginx = lib.mkIf (cfg.instances != {}) {
+      enable = true;
+    };
+
+    services = {
+      anubis = {
+        defaultOptions.settings.COOKIE_DYNAMIC_DOMAIN = true;
+        instances = anubisInstances;
+      };
+
+      nginx = {
+        enable = true;
+
+        recommendedTlsSettings = true;
+        recommendedOptimisation = true;
+        recommendedGzipSettings = true;
+        recommendedProxySettings = true;
+
+        virtualHosts = nginxVirtualHosts;
+      };
+    };
+  };
+}
diff --git a/modules/by-name/at/atuin-sync/module.nix b/modules/by-name/at/atuin-sync/module.nix
index 0db2e29..e0d75bb 100644
--- a/modules/by-name/at/atuin-sync/module.nix
+++ b/modules/by-name/at/atuin-sync/module.nix
@@ -19,17 +19,9 @@ in {
   config = lib.mkIf cfg.enable {
     vhack.nginx.enable = true;
 
-    services = {
-      nginx.virtualHosts."${cfg.fqdn}" = {
-        locations."/" = {
-          proxyPass = "http://127.0.0.1:${toString config.services.atuin.port}";
-          recommendedProxySettings = true;
-        };
-
-        enableACME = true;
-        forceSSL = true;
-      };
+    vhack.anubis.instances."${cfg.fqdn}".target = "http://127.0.0.1:${toString config.services.atuin.port}";
 
+    services = {
       atuin = {
         enable = true;
         package = vhackPackages.atuin-server-only;
diff --git a/modules/by-name/co/constants/module.nix b/modules/by-name/co/constants/module.nix
index 1513b0c..3de9608 100644
--- a/modules/by-name/co/constants/module.nix
+++ b/modules/by-name/co/constants/module.nix
@@ -53,6 +53,8 @@
       sharkey = 339;
       redis-sharkey = 340;
       grocy = 341;
+      anubis = 342;
+      postfix-tlspol = 343;
 
       # As per the NixOS file, the uids should not be greater or equal to 400;
     };
@@ -64,6 +66,7 @@
       inherit
         (uids)
         acme
+        anubis
         dhcpcd
         etebase-server
         knot-resolver
@@ -75,6 +78,7 @@
         nscd
         opendkim
         peertube
+        postfix-tlspol
         redis-mastodon
         redis-nextcloud
         redis-peertube
diff --git a/modules/by-name/et/etesync/module.nix b/modules/by-name/et/etesync/module.nix
index bcabc8a..4dc8575 100644
--- a/modules/by-name/et/etesync/module.nix
+++ b/modules/by-name/et/etesync/module.nix
@@ -45,26 +45,14 @@ in {
     ];
 
     services.nginx = {
-      enable = true;
-      recommendedTlsSettings = true;
-      recommendedOptimisation = true;
-      recommendedGzipSettings = true;
-      recommendedProxySettings = true;
-
       virtualHosts = {
         "etebase.vhack.eu" = {
-          enableACME = true;
-          forceSSL = true;
-
           locations = {
             # TODO: Maybe fix permissions to use pregenerated static files which would
             # improve performance.
             #"/static" = {
             #  root = config.services.etebase-server.settings.global.static_root;
             #};
-            "/" = {
-              proxyPass = "http://127.0.0.1:${builtins.toString config.services.etebase-server.port}";
-            };
           };
           serverAliases = [
             "dav.vhack.eu"
@@ -72,6 +60,8 @@ in {
         };
       };
     };
+    vhack.anubis.instances."etebase.vhack.eu".target = "http://127.0.0.1:${builtins.toString config.services.etebase-server.port}";
+
     users = {
       users.etebase-server.uid = config.vhack.constants.ids.uids.etebase-server;
       groups.etebase-server.gid = config.vhack.constants.ids.gids.etebase-server;
diff --git a/modules/by-name/gi/git-back/module.nix b/modules/by-name/gi/git-back/module.nix
index 96f4913..7df1bac 100644
--- a/modules/by-name/gi/git-back/module.nix
+++ b/modules/by-name/gi/git-back/module.nix
@@ -28,14 +28,6 @@ in {
       };
     };
 
-    services.nginx = {
-      enable = true;
-      virtualHosts."${cfg.domain}" = {
-        locations."/".proxyPass = "http://127.0.0.1:8000";
-
-        enableACME = true;
-        forceSSL = true;
-      };
-    };
+    vhack.anubis.instances."${cfg.domain}".target = "http://127.0.0.1:8000";
   };
 }
diff --git a/modules/by-name/ma/mail/module.nix b/modules/by-name/ma/mail/module.nix
index 55f2fb8..500abd0 100644
--- a/modules/by-name/ma/mail/module.nix
+++ b/modules/by-name/ma/mail/module.nix
@@ -73,6 +73,8 @@ in {
       enable = true;
       inherit (cfg) fqdn;
 
+      stateVersion = 3;
+
       useFsLayout = true;
 
       extraVirtualAliases = {
@@ -156,11 +158,13 @@ in {
         knot-resolver.uid = config.vhack.constants.ids.uids.knot-resolver;
         redis-rspamd.uid = config.vhack.constants.ids.uids.redis-rspamd;
         rspamd.uid = config.vhack.constants.ids.uids.rspamd;
+        postfix-tlspol.uid = config.vhack.constants.ids.uids.postfix-tlspol;
       };
       groups = {
         knot-resolver.gid = lib.mkForce config.vhack.constants.ids.gids.knot-resolver;
         redis-rspamd.gid = config.vhack.constants.ids.gids.redis-rspamd;
         rspamd.gid = config.vhack.constants.ids.gids.rspamd;
+        postfix-tlspol.gid = config.vhack.constants.ids.gids.postfix-tlspol;
       };
     };
   };
diff --git a/modules/by-name/ma/matrix/module.nix b/modules/by-name/ma/matrix/module.nix
index ae3f04e..39631ef 100644
--- a/modules/by-name/ma/matrix/module.nix
+++ b/modules/by-name/ma/matrix/module.nix
@@ -62,10 +62,12 @@ in {
       tmpfiles.rules = [
         "d /etc/matrix 0755 matrix-synapse matrix-synapse"
       ];
-      services.postgresql.postStart = ''
-        $PSQL -tAc "ALTER ROLE \"matrix-synapse\" WITH PASSWORD 'synapse';"
-        $PSQL -tAc "ALTER ROLE \"mautrix-whatsapp\" WITH PASSWORD 'whatsapp';"
-      '';
+      # TODO: Do we still need this? <2025-12-18>
+      # The `$PSQL` env var seemed to go away between the 25.05 -> 25.11 update
+      # services.postgresql.postStart = ''
+      #   $PSQL -tAc "ALTER ROLE \"matrix-synapse\" WITH PASSWORD 'synapse';"
+      #   $PSQL -tAc "ALTER ROLE \"mautrix-whatsapp\" WITH PASSWORD 'whatsapp';"
+      # '';
     };
 
     services = {
diff --git a/modules/by-name/ne/nextcloud/module.nix b/modules/by-name/ne/nextcloud/module.nix
index e0d7cb3..3e1ef3e 100644
--- a/modules/by-name/ne/nextcloud/module.nix
+++ b/modules/by-name/ne/nextcloud/module.nix
@@ -10,7 +10,7 @@ in {
     enable = lib.mkEnableOption "a sophisticated nextcloud setup";
     package = lib.mkOption {
       type = lib.types.package;
-      default = pkgs.nextcloud31;
+      default = pkgs.nextcloud32;
       description = "The nextcloud package to use";
     };
     hostname = lib.mkOption {
@@ -22,6 +22,7 @@ in {
       description = "The age encrypted admin password file";
     };
   };
+
   config = lib.mkIf cfg.enable {
     vhack = {
       nginx.enable = true;
@@ -71,7 +72,10 @@ in {
     users = {
       users = {
         "nextcloud".uid = config.vhack.constants.ids.uids.nextcloud;
-        "redis-nextcloud".uid = config.vhack.constants.ids.uids.redis-nextcloud;
+        "redis-nextcloud" = {
+          uid = config.vhack.constants.ids.uids.redis-nextcloud;
+          group = "redis-nextcloud";
+        };
       };
       groups = {
         "nextcloud".gid = config.vhack.constants.ids.gids.nextcloud;
diff --git a/modules/by-name/re/redlib/module.nix b/modules/by-name/re/redlib/module.nix
index 909c9f1..4d3c600 100644
--- a/modules/by-name/re/redlib/module.nix
+++ b/modules/by-name/re/redlib/module.nix
@@ -23,14 +23,6 @@ in {
       openFirewall = false;
     };
 
-    services.nginx = {
-      enable = true;
-      virtualHosts.${domain} = {
-        locations."/".proxyPass = "http://127.0.0.1:${toString config.services.redlib.port}";
-
-        enableACME = true;
-        forceSSL = true;
-      };
-    };
+    vhack.anubis.instances."${domain}".target = "http://127.0.0.1:${toString config.services.redlib.port}";
   };
 }
diff --git a/modules/by-name/ru/rust-motd/module.nix b/modules/by-name/ru/rust-motd/module.nix
index 8d0939a..bf23843 100644
--- a/modules/by-name/ru/rust-motd/module.nix
+++ b/modules/by-name/ru/rust-motd/module.nix
@@ -21,7 +21,7 @@
   userList = builtins.mapAttrs (n: v: 2) (lib.filterAttrs pred config.users.users);
 
   bannerFile =
-    pkgs.runCommandNoCCLocal "banner-file" {
+    pkgs.runCommandLocal "banner-file" {
       nativeBuildInputs = [pkgs.figlet];
     } ''
       echo "${config.system.name}" | figlet -f slant > "$out"
diff --git a/modules/by-name/sh/sharkey/module.nix b/modules/by-name/sh/sharkey/module.nix
index 155d658..18bf394 100644
--- a/modules/by-name/sh/sharkey/module.nix
+++ b/modules/by-name/sh/sharkey/module.nix
@@ -3,22 +3,11 @@
   lib,
   pkgs,
   pkgsUnstable,
-  nixpkgs-unstable,
   ...
 }: let
   cfg = config.vhack.sharkey;
 in {
-  imports = [
-    # TODO(@bpeetz): Remove this import once we update to NixOS 25.11 <2025-07-12>
-    "${nixpkgs-unstable}/nixos/modules/services/web-apps/sharkey.nix"
-  ];
-
   options = {
-    services.meilisearch.settings = lib.mkOption {
-      type = lib.types.attrsOf lib.type.anything;
-      default = {};
-    };
-
     vhack.sharkey = {
       enable = lib.mkEnableOption "sharkey";
 
@@ -88,14 +77,10 @@ in {
     };
 
     systemd.services.sharkey = {
-      # TODO(@bpeetz): `postgresql.target` is only available in NixOS 25.11, as such we
-      # need to override this back to the postgresql.service. <2025-07-12>
-      after = lib.mkForce [
-        "postgresql.service"
+      after = [
         "redis-sharkey.service"
       ];
-      bindsTo = lib.mkForce [
-        "postgresql.service"
+      bindsTo = [
         "redis-sharkey.service"
       ];
 
diff --git a/modules/by-name/st/stalwart-mail/module.nix b/modules/by-name/st/stalwart-mail/module.nix
index 4565bf4..f7e44d8 100644
--- a/modules/by-name/st/stalwart-mail/module.nix
+++ b/modules/by-name/st/stalwart-mail/module.nix
@@ -18,7 +18,7 @@ in {
   options.vhack.stalwart-mail = {
     enable = lib.mkEnableOption "starwart-mail";
 
-    package = lib.mkPackageOption vhackPackages "stalwart-mail-patched" {};
+    package = lib.mkPackageOption pkgs "stalwart-mail" {};
 
     admin = lib.mkOption {
       description = ''
diff --git a/modules/by-name/st/stalwart-mail/settings.nix b/modules/by-name/st/stalwart-mail/settings.nix
index 907cea9..eb53783 100644
--- a/modules/by-name/st/stalwart-mail/settings.nix
+++ b/modules/by-name/st/stalwart-mail/settings.nix
@@ -197,7 +197,7 @@ in {
 
       # Fetch the newest spam-filter rules not from github, but from the nix
       # package.
-      resource = "file://${cfg.package.passthru.spamfilter}/spam-filter.toml";
+      resource = "file://${cfg.package.passthru.spam-filter}/spam-filter.toml";
       auto-update = false;
     };
 
diff --git a/scripts/build.sh b/scripts/build.sh
new file mode 100755
index 0000000..a3ff064
--- /dev/null
+++ b/scripts/build.sh
@@ -0,0 +1,7 @@
+#! /usr/bin/env sh
+
+for host in "server2" "server3"; do
+    nix build ".#nixosConfigurations.$host.config.system.build.toplevel" --print-out-paths --no-link --option max-jobs 1
+done
+
+# vim: ft=sh
diff --git a/scripts/check.sh b/scripts/check.sh
new file mode 100755
index 0000000..f152cbb
--- /dev/null
+++ b/scripts/check.sh
@@ -0,0 +1,20 @@
+#! /usr/bin/env sh
+
+# --log-format multiline-with-logs \
+nix build \
+    --option max-jobs 1 \
+    --print-out-paths --no-link \
+    .#checks.x86_64-linux.atuin-sync \
+    .#checks.x86_64-linux.back \
+    .#checks.x86_64-linux.deploy-activate \
+    .#checks.x86_64-linux.deploy-schema \
+    .#checks.x86_64-linux.dns \
+    .#checks.x86_64-linux.formatting \
+    .#checks.x86_64-linux.git-server \
+    .#checks.x86_64-linux.rust-motd \
+    .#checks.x86_64-linux.sharkey \
+    .#checks.x86_64-linux.sharkey-cpu \
+    .#checks.x86_64-linux.taskchampion-sync
+# .#checks.x86_64-linux.email-dns \
+# .#checks.x86_64-linux.email-http \
+# .#checks.x86_64-linux.email-ip \
diff --git a/scripts/test.sh b/scripts/test.sh
new file mode 100755
index 0000000..58c3343
--- /dev/null
+++ b/scripts/test.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env sh
+
+test_target="$1"
+
+[ -z "$test_target" ] && {
+    echo "You need to select a test target!" 1>&2
+    echo "Usage: test_interactive TEST_TARGET" 1>&2
+    exit 1
+}
+
+nix build --log-format multiline-with-logs .#checks.x86_64-linux."$test_target"
+# vim: ft=sh
diff --git a/tests/by-name/at/atuin-sync/test.nix b/tests/by-name/at/atuin-sync/test.nix
index d29c031..d65c216 100644
--- a/tests/by-name/at/atuin-sync/test.nix
+++ b/tests/by-name/at/atuin-sync/test.nix
@@ -154,14 +154,12 @@ nixos-lib.runTest {
       client1.wait_until_succeeds("curl https://atuin-sync.server")
 
       with subtest("Setup client syncing"):
+          # See https://docs.atuin.sh/guide/sync/
           for client in [client1, client2]:
             client.succeed("${mkSyncConfig}")
 
           client1.succeed("${syncRegister}")
-
-          for client in [client1, client2]:
-            # See https://docs.atuin.sh/guide/sync/
-            client.succeed(f"${syncLogin} '{client1.succeed("atuin key")}'")
+          client2.succeed(f"${syncLogin} '{client1.succeed("atuin key")}'")
 
       with subtest("Can import shell history"):
           client1.succeed("${runCommandAndRecordInAtuin} echo hi - client 1")
diff --git a/tests/by-name/ba/back/test.nix b/tests/by-name/ba/back/test.nix
index cce5ede..41d6c8e 100644
--- a/tests/by-name/ba/back/test.nix
+++ b/tests/by-name/ba/back/test.nix
@@ -109,6 +109,12 @@ in
 
 
       with subtest("admin can clone and configure gitolite-admin.git"):
+        server.succeed("sudo -u git ${pkgs.writeShellScript "delete_main_branch_on_server" ''
+        set -xe
+
+        cd ~git/repositories/gitolite-admin.git
+        git branch --move --force main master
+      ''}")
         client.succeed("${pkgs.writeShellScript "setup-gitolite-admin.git" ''
         set -xe
 
@@ -118,12 +124,9 @@ in
 
         cp ${sshKeys.alice.pub} gitolite-admin/keydir/alice.pub
 
-        (cd gitolite-admin && git switch -c master && git branch -D main)
-
         (cd gitolite-admin && git add . && git commit -m 'Add keys for alice' && git push -u origin master)
         cat ${gitoliteAdminConfSnippet} >> gitolite-admin/conf/gitolite.conf
         (cd gitolite-admin && git add . && git commit -m 'Add support for wild repos' && git push)
-        (cd gitolite-admin && git push -d origin main)
       ''}")
 
       with subtest("alice can create a repo"):
diff --git a/tests/by-name/gi/git-server/test.nix b/tests/by-name/gi/git-server/test.nix
index 5cd8c33..524efcb 100644
--- a/tests/by-name/gi/git-server/test.nix
+++ b/tests/by-name/gi/git-server/test.nix
@@ -122,6 +122,12 @@ in
 
 
       with subtest("admin can clone and configure gitolite-admin.git"):
+        server.succeed("sudo -u git ${pkgs.writeShellScript "delete_main_branch_on_server" ''
+        set -xe
+
+        cd ~git/repositories/gitolite-admin.git
+        git branch --move --force main master
+      ''}")
         client.succeed("${pkgs.writeShellScript "setup-gitolite-admin.git" ''
         set -xe
 
@@ -132,12 +138,9 @@ in
         cp ${sshKeys.alice.pub} gitolite-admin/keydir/alice.pub
         cp ${sshKeys.bob.pub} gitolite-admin/keydir/bob.pub
 
-        (cd gitolite-admin && git switch -c master && git branch -D main)
-
         (cd gitolite-admin && git add . && git commit -m 'Add keys for alice, bob' && git push -u origin master)
         cat ${gitoliteAdminConfSnippet} >> gitolite-admin/conf/gitolite.conf
         (cd gitolite-admin && git add . && git commit -m 'Add support for wild repos' && git push)
-        (cd gitolite-admin && git push -d origin main)
       ''}")
 
         server.succeed("${pkgs.writeShellScript "verify gitolite-admin.conf" ''
diff --git a/update.sh b/update.sh
index 669ab7a..903b0ea 100755
--- a/update.sh
+++ b/update.sh
@@ -13,8 +13,7 @@ __update_sh_run() {
 __update_sh_run nix flake update
 __update_sh_run ./pkgs/update_pkgs.sh "$@"
 
-
 for host in "server2" "server3"; do
-    nix build ".#nixosConfigurations.$host.config.system.build.toplevel" --print-out-paths --no-link --option max-jobs 1
+    __update_sh_run nix build ".#nixosConfigurations.$host.config.system.build.toplevel" --print-out-paths --no-link --option max-jobs 1
 done
 # vim: ft=sh