about summary refs log tree commit diff stats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/by-name/an/anubis/module.nix94
-rw-r--r--modules/by-name/at/atuin-sync/module.nix37
-rw-r--r--modules/by-name/ba/back/module.nix92
-rw-r--r--modules/by-name/co/constants/module.nix6
-rw-r--r--modules/by-name/et/etesync/module.nix14
-rw-r--r--modules/by-name/gi/git-back/module.nix33
-rw-r--r--modules/by-name/gr/grocy/module.nix51
-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.nix12
-rw-r--r--modules/by-name/re/redlib/module.nix15
-rw-r--r--modules/by-name/ru/rust-motd/module.nix32
-rw-r--r--modules/by-name/sh/sharkey/module.nix301
-rw-r--r--modules/by-name/st/stalwart-mail/module.nix2
-rw-r--r--modules/by-name/st/stalwart-mail/settings.nix2
-rw-r--r--modules/by-name/ta/taskchampion-sync/module.nix43
-rw-r--r--modules/by-name/us/users/module.nix30
17 files changed, 381 insertions, 397 deletions
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
new file mode 100644
index 0000000..e0d75bb
--- /dev/null
+++ b/modules/by-name/at/atuin-sync/module.nix
@@ -0,0 +1,37 @@
+{
+  config,
+  lib,
+  vhackPackages,
+  ...
+}: let
+  cfg = config.vhack.atuin-sync;
+in {
+  options.vhack.atuin-sync = {
+    enable = lib.mkEnableOption "atuin sync server";
+
+    fqdn = lib.mkOption {
+      description = "The fully qualified domain name of this instance.";
+      type = lib.types.str;
+      example = "atuin-sync.atuin.sh";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    vhack.nginx.enable = 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;
+        host = "127.0.0.1";
+
+        # Nobody knows about the fqdn and even if, they can only upload encrypted blobs.
+        openRegistration = true;
+
+        database.createLocally = true;
+      };
+    };
+  };
+}
diff --git a/modules/by-name/ba/back/module.nix b/modules/by-name/ba/back/module.nix
deleted file mode 100644
index d47ffce..0000000
--- a/modules/by-name/ba/back/module.nix
+++ /dev/null
@@ -1,92 +0,0 @@
-{
-  config,
-  lib,
-  vhackPackages,
-  pkgs,
-  ...
-}: let
-  cfg = config.vhack.back;
-in {
-  options.vhack.back = {
-    enable = lib.mkEnableOption "Back issue tracker (inspired by tvix's panettone)";
-
-    domain = lib.mkOption {
-      type = lib.types.str;
-      description = "The domain to host this `back` instance on.";
-    };
-
-    settings = {
-      scan_path = lib.mkOption {
-        type = lib.types.path;
-        description = "The path to the directory under which all the repositories reside";
-      };
-      project_list = lib.mkOption {
-        type = lib.types.path;
-        description = "The path to the `projects.list` file.";
-      };
-
-      source_code_repository_url = lib.mkOption {
-        description = "The url to the source code of this instance of back";
-        default = "https://git.foss-syndicate.org/vhack.eu/nixos-server/tree/pkgs/by-name/ba/back";
-        type = lib.types.str;
-      };
-
-      root_url = lib.mkOption {
-        type = lib.types.str;
-        description = "The url to this instance of back.";
-        default = "https://${cfg.domain}";
-      };
-    };
-  };
-
-  config = lib.mkIf cfg.enable {
-    systemd.services."back" = {
-      description = "Back issue tracking system.";
-      requires = ["network-online.target"];
-      after = ["network-online.target"];
-      wantedBy = ["default.target"];
-
-      serviceConfig = {
-        ExecStart = "${lib.getExe vhackPackages.back} ${(pkgs.formats.json {}).generate "config.json" cfg.settings}";
-
-        # Ensure that the service can read the repository
-        # FIXME(@bpeetz): This has the implied assumption, that all the exposed git
-        # repositories are readable for the git group. This should not be necessary. <2024-12-23>
-        User = "git";
-        Group = "git";
-
-        DynamicUser = true;
-        Restart = "always";
-
-        # Sandboxing
-        ProtectSystem = "strict";
-        ProtectHome = true;
-        PrivateTmp = true;
-        PrivateDevices = true;
-        ProtectHostname = true;
-        ProtectClock = true;
-        ProtectKernelTunables = true;
-        ProtectKernelModules = true;
-        ProtectKernelLogs = true;
-        ProtectControlGroups = true;
-        RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
-        RestrictNamespaces = true;
-        LockPersonality = true;
-        MemoryDenyWriteExecute = true;
-        RestrictRealtime = true;
-        RestrictSUIDSGID = true;
-        RemoveIPC = true;
-        PrivateMounts = true;
-        # System Call Filtering
-        SystemCallArchitectures = "native";
-        SystemCallFilter = ["~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid"];
-      };
-    };
-    services.nginx.virtualHosts."${cfg.domain}" = {
-      locations."/".proxyPass = "http://127.0.0.1:8000";
-
-      enableACME = true;
-      forceSSL = true;
-    };
-  };
-}
diff --git a/modules/by-name/co/constants/module.nix b/modules/by-name/co/constants/module.nix
index 2115a37..3de9608 100644
--- a/modules/by-name/co/constants/module.nix
+++ b/modules/by-name/co/constants/module.nix
@@ -52,6 +52,9 @@
       stalwart-mail-certificates = 338; # GROUP
       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;
     };
@@ -63,6 +66,7 @@
       inherit
         (uids)
         acme
+        anubis
         dhcpcd
         etebase-server
         knot-resolver
@@ -74,6 +78,7 @@
         nscd
         opendkim
         peertube
+        postfix-tlspol
         redis-mastodon
         redis-nextcloud
         redis-peertube
@@ -85,6 +90,7 @@
         systemd-oom
         sharkey
         redis-sharkey
+        grocy
         systemd-coredump # matches systemd-coredump user
         resolvconf # This group is not matched to an user?
         stalwart-mail-certificates # This group is used to connect nginx and stalwart-mail
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
new file mode 100644
index 0000000..7df1bac
--- /dev/null
+++ b/modules/by-name/gi/git-back/module.nix
@@ -0,0 +1,33 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.vhack.git-back;
+in {
+  options.vhack.git-back = {
+    enable = lib.mkEnableOption "Back integration into git-server";
+
+    domain = lib.mkOption {
+      type = lib.types.str;
+      description = "The domain where to deploy back";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    vhack.back = {
+      enable = true;
+
+      user = "git";
+      group = "git";
+
+      settings = {
+        scan_path = "${config.services.gitolite.dataDir}/repositories";
+        project_list = "${config.services.gitolite.dataDir}/projects.list";
+        root_url = "https://${cfg.domain}";
+      };
+    };
+
+    vhack.anubis.instances."${cfg.domain}".target = "http://127.0.0.1:8000";
+  };
+}
diff --git a/modules/by-name/gr/grocy/module.nix b/modules/by-name/gr/grocy/module.nix
new file mode 100644
index 0000000..28107f2
--- /dev/null
+++ b/modules/by-name/gr/grocy/module.nix
@@ -0,0 +1,51 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.vhack.grocy;
+  data = "/var/lib/grocy";
+in {
+  options.vhack.grocy = {
+    enable = lib.mkEnableOption "grocy";
+
+    domain = lib.mkOption {
+      type = lib.types.str;
+      description = "FQDN for the grocy instance.";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    services.grocy = {
+      enable = true;
+
+      hostName = cfg.domain;
+      dataDir = data;
+
+      settings = {
+        currency = "EUR";
+        culture = "sv_SE";
+        calendar.firstDayOfWeek = 1;
+      };
+    };
+
+    vhack.persist.directories = [
+      {
+        directory = data;
+        user = "grocy";
+        group = "grocy";
+        mode = "0700";
+      }
+    ];
+
+    users = {
+      groups.grocy = {
+        gid = config.vhack.constants.ids.gids.grocy;
+      };
+      users.grocy = {
+        extraGroups = ["grocy"];
+        uid = config.vhack.constants.ids.uids.grocy;
+      };
+    };
+  };
+}
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 f34ecf4..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 ENCRYPTED PASSWORD 'synapse';"
-        $PSQL -tAc "ALTER ROLE mautrix-whatsapp WITH ENCRYPTED 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 2e40970..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;
@@ -42,6 +43,10 @@ in {
     services = {
       nextcloud = {
         enable = true;
+        extraApps = {
+          inherit (cfg.package.packages.apps) calendar contacts tasks;
+        };
+        extraAppsEnable = true;
         configureRedis = true;
         config = {
           adminuser = "admin";
@@ -67,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 eb5edba..4d3c600 100644
--- a/modules/by-name/re/redlib/module.nix
+++ b/modules/by-name/re/redlib/module.nix
@@ -23,19 +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;
-      };
-    };
-
-    # TODO(@bpeetz): Remove this at some point. <2025-02-04>
-    vhack.nginx.redirects = {
-      "libreddit.vhack.eu" = "${domain}";
-    };
+    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 a6998f4..bf23843 100644
--- a/modules/by-name/ru/rust-motd/module.nix
+++ b/modules/by-name/ru/rust-motd/module.nix
@@ -19,6 +19,13 @@
     || v.openssh.authorizedKeys.keyFiles != []
   );
   userList = builtins.mapAttrs (n: v: 2) (lib.filterAttrs pred config.users.users);
+
+  bannerFile =
+    pkgs.runCommandLocal "banner-file" {
+      nativeBuildInputs = [pkgs.figlet];
+    } ''
+      echo "${config.system.name}" | figlet -f slant > "$out"
+    '';
 in {
   options.vhack.rust-motd = {
     enable = lib.mkEnableOption "rust-motd";
@@ -49,25 +56,22 @@ in {
 
         banner = {
           color = "red";
-          command = "${pkgs.hostname}/bin/hostname | ${pkgs.figlet}/bin/figlet -f slant";
-          # if you don't want a dependency on figlet, you can generate your
-          # banner however you want, put it in a file, and then use something like:
-          # command = "cat banner.txt"
+          # Avoid some runtime dependencies.
+          command = "cat ${bannerFile}";
+        };
+
+        cg_stats = {
+          state_file = "/var/lib/rust-motd/cg_stats_state";
+          threshold = 0.02; # When to start generating output for a cgroup
+        };
+        load_avg = {
+          format = "Load (1, 5, 15 min.): {one:.02}, {five:.02}, {fifteen:.02}";
         };
 
         uptime = {
           prefix = "Uptime:";
         };
 
-        # ssl_certificates = {
-        #   sort_method = "manual";
-        #
-        #   certs = {
-        #     "server1.vhack.eu" = "/var/lib/acme/server1.vhack.eu/cert.pem";
-        #     "vhack.eu" = "/var/lib/acme/vhack.eu/cert.pem";
-        #   };
-        # };
-
         filesystems = {
           root = "/";
           persistent = "/srv";
@@ -79,7 +83,7 @@ in {
           swap_pos = "beside"; # or "below" or "none"
         };
 
-        fail2_ban = {
+        fail_2_ban = {
           jails = ["sshd"]; #, "anotherjail"]
         };
 
diff --git a/modules/by-name/sh/sharkey/module.nix b/modules/by-name/sh/sharkey/module.nix
index a2f5445..18bf394 100644
--- a/modules/by-name/sh/sharkey/module.nix
+++ b/modules/by-name/sh/sharkey/module.nix
@@ -1,276 +1,115 @@
-# Source: https://github.com/sodiboo/system/blob/b63c7b27f49043e8701b3ff5e1441cd27d5a2fff/sharkey/module.nix
 {
   config,
   lib,
   pkgs,
-  vhackPackages,
+  pkgsUnstable,
   ...
 }: let
   cfg = config.vhack.sharkey;
-
-  createDB = cfg.database.host == "127.0.0.1" && cfg.database.createLocally;
-
-  settingsFormat = pkgs.formats.yaml {};
-  configFile = settingsFormat.generate "sharkey-config.yml" cfg.settings;
 in {
-  options.vhack.sharkey = {
-    enable = lib.mkEnableOption "sharkey";
-
-    fqdn = lib.mkOption {
-      description = "The fully qualified domain name of this instance.";
-      type = lib.types.str;
-      example = "sharkey.shonk.social";
-    };
-
-    package = lib.mkOption {
-      type = lib.types.package;
-      default = vhackPackages.sharkey;
-      defaultText = lib.literalExpression "vhackPackages.sharkey";
-      description = "Sharkey package to use.";
-    };
-
-    dataDirectory = lib.mkOption {
-      type = lib.types.path;
-      default = "/var/lib/sharkey";
-      description = "The directory where sharkey stores it's data.";
-
-      # This is already set in the package.
-      readOnly = true;
-    };
-
-    database = {
-      createLocally = lib.mkOption {
-        description = "Whether to enable local db creation.";
-        type = lib.types.bool;
-        default = true;
-      };
+  options = {
+    vhack.sharkey = {
+      enable = lib.mkEnableOption "sharkey";
 
-      host = lib.mkOption {
+      fqdn = lib.mkOption {
+        description = "The fully qualified domain name of this instance.";
         type = lib.types.str;
-        default = "127.0.0.1";
-        description = "The database host.";
+        example = "sharkey.shonk.social";
       };
 
-      port = lib.mkOption {
-        type = lib.types.port;
-        default = 5432;
-        description = "The database port.";
+      package = lib.mkOption {
+        type = lib.types.package;
+        default = pkgsUnstable.sharkey;
+        defaultText = lib.literalExpression "vhackPackages.sharkey";
+        description = "Sharkey package to use.";
       };
 
-      name = lib.mkOption {
-        type = lib.types.str;
-        default = "sharkey";
-        description = "The database name in postgresql.";
+      mediaDirectory = lib.mkOption {
+        type = lib.types.path;
+        default = "/var/lib/sharkey";
+        description = "The directory where sharkey stores it's data.";
       };
-    };
 
-    settings = lib.mkOption {
-      inherit (settingsFormat) type;
-      default = {};
-      description = ''
-        Configuration for Sharkey, see
-        <link xlink:href="https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/.config/example.yml"/>
-        for supported settings.
-      '';
+      settings = lib.mkOption {
+        inherit (pkgs.formats.yaml {}) type;
+        default = {};
+        description = ''
+          Extra Configuration for Sharkey, see
+          <link xlink:href="https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/.config/example.yml"/>
+          for supported settings.
+
+          Note, that this is applied on-top of the neccessary config.
+        '';
+      };
     };
   };
 
   config = lib.mkIf cfg.enable {
-    environment.systemPackages = [cfg.package];
-
-    vhack = {
-      nginx.enable = true;
+    services = {
+      sharkey = {
+        enable = true;
 
-      sharkey.settings = {
-        id = "aidx";
+        inherit (cfg) package;
+        openFirewall = false;
+        setupRedis = true;
+        setupPostgresql = true;
 
-        url = "https://${cfg.fqdn}/";
-        port = 5312;
+        settings =
+          cfg.settings
+          // {
+            url = "https://${cfg.fqdn}/";
+            port = 5312;
 
-        db = {
-          inherit (cfg.database) host port;
-          db = cfg.database.name;
-          user = cfg.database.name;
-          pass = "sharkey-password";
-        };
-        redis = {
-          path = config.services.redis.servers."sharkey".unixSocket;
-        };
+            inherit (cfg) mediaDirectory;
+            fulltextSearch.provider = "sqlLike";
+          };
       };
 
-      persist.directories = [
-        {
-          directory = "${config.services.redis.servers."sharkey".settings.dir}";
-          user = "sharkey";
-          group = "redis-sharey";
-          mode = "0770";
-        }
-        {
-          directory = "${cfg.dataDirectory}";
-          user = "sharkey";
-          group = "sharkey";
-          mode = "0770";
-        }
-      ];
-    };
-
-    services = {
       nginx.virtualHosts."${cfg.fqdn}" = {
         locations."/" = {
-          proxyPass = "http://127.0.0.1:${toString cfg.settings.port}";
+          proxyPass = "http://127.0.0.1:${toString config.services.sharkey.settings.port}";
           proxyWebsockets = true;
         };
 
-        # proxy_set_header Host $host;
-        # proxy_http_version 1.1;
-        # proxy_redirect off;
-        #
-        # # If it's behind another reverse proxy or CDN, remove the following.
-        # proxy_set_header X-Real-IP $remote_addr;
-        # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-        # proxy_set_header X-Forwarded-Proto https;
-        #
-        # # For WebSocket
-        # proxy_set_header Upgrade $http_upgrade;
-        # proxy_set_header Connection $connection_upgrade;
-        #
-        # # Cache settings
-        # proxy_cache cache1;
-        # proxy_cache_lock on;
-        # proxy_cache_use_stale updating;
-        # proxy_force_ranges on;
-        # add_header X-Cache $upstream_cache_status;
-
         enableACME = true;
         forceSSL = true;
       };
-
-      postgresql = lib.mkIf createDB {
-        enable = true;
-        settings.port = cfg.database.port;
-        ensureUsers = [
-          {
-            inherit (cfg.database) name;
-            ensureDBOwnership = true;
-          }
-        ];
-        ensureDatabases = [cfg.database.name];
-      };
-
-      redis = {
-        servers."sharkey" = {
-          enable = true;
-
-          user = "sharkey";
-
-          # Disable TCP listening. (We have a UNIX socket)
-          port = 0;
-          bind = null;
-
-          settings = {
-            protected-mode = true;
-            enable-protected-configs = false;
-            enable-debug-command = false;
-            enable-module-command = false;
-
-            supervised = "systemd";
-            stop-writes-on-bgsave-error = true;
-            sanitize-dump-payload = "clients";
-          };
-        };
-      };
     };
 
-    systemd.services.postgresql.postStart = ''
-      $PSQL -tAc "ALTER ROLE ${cfg.database.name} WITH ENCRYPTED PASSWORD 'sharkey-password';"
-    '';
-
     systemd.services.sharkey = {
-      requires =
-        [
-          "redis-sharkey.service"
-          "network-online.target"
-        ]
-        ++ lib.optionals createDB ["postgresql.service"];
-
-      after =
-        [
-          "redis-sharkey.service"
-          "network-online.target"
-        ]
-        ++ lib.optionals createDB ["postgresql.service"];
-
-      wantedBy = ["multi-user.target"];
-
-      environment = {
-        MISSKEY_CONFIG_YML = "${configFile}";
-        NODE_ENV = "production";
-      };
+      after = [
+        "redis-sharkey.service"
+      ];
+      bindsTo = [
+        "redis-sharkey.service"
+      ];
 
       serviceConfig = {
-        Type = "simple";
-
-        StateDirectory = "sharkey";
-        StateDirectoryMode = "0700";
-        CacheDirectory = "sharkey";
-        RuntimeDirectory = "sharkey";
-        RuntimeDirectoryMode = "0700";
-        ExecStart = "${lib.getExe cfg.package} migrateandstart";
-
-        TimeoutSec = 60;
-        Restart = "no";
-
-        StandardOutput = "journal";
-        StandardError = "journal";
-        SyslogIdentifier = "sharkey";
-
+        # The upstream service uses DynamicUsers, which currently poses issues to our
+        # directory persisting strategy.
         User = "sharkey";
         Group = "sharkey";
+        DynamicUser = lib.mkForce false;
+      };
+    };
 
-        # Bind standard privileged ports
-        AmbientCapabilities = [];
-        CapabilityBoundingSet = [];
-
-        ReadWritePaths = [
-          "${cfg.dataDirectory}"
-        ];
+    vhack = {
+      nginx.enable = true;
 
-        # Hardening
-        DeviceAllow = [""];
-        LockPersonality = true;
-        # Probably needed for v8's JIT (crashes with it on).
-        MemoryDenyWriteExecute = false;
-        PrivateDevices = true;
-        PrivateUsers = true;
-        ProcSubset = "pid";
-        PrivateTmp = true;
-        ProtectClock = true;
-        ProtectControlGroups = true;
-        ProtectHome = true;
-        ProtectHostname = true;
-        ProtectKernelLogs = true;
-        ProtectKernelModules = true;
-        ProtectKernelTunables = true;
-        ProtectProc = "invisible";
-        ProtectSystem = "strict";
-        RestrictAddressFamilies = [
-          "AF_UNIX" # Local communication                        unix(7)
-          "AF_INET" # IPv4 Internet protocols                    ip(7)
-          "AF_INET6" # IPv6 Internet protocols                   ipv6(7)
-          # Needed for nodes `os.networkInterfaces()` function.
-          "AF_NETLINK" # Kernel user interface device            netlink(7)
-        ];
-        RestrictNamespaces = true;
-        RestrictRealtime = true;
-        RestrictSUIDSGID = true;
-        SystemCallArchitectures = "native";
-        SystemCallFilter = [
-          "@system-service"
-          "~@privileged"
-          "~@mount"
-        ];
-        UMask = "0077";
-      };
+      persist.directories = [
+        {
+          directory = "${config.services.redis.servers."sharkey".settings.dir}";
+          user = "sharkey";
+          group = "redis-sharey";
+          mode = "0770";
+        }
+        {
+          directory = "${cfg.mediaDirectory}";
+          user = "sharkey";
+          group = "sharkey";
+          mode = "0700";
+        }
+      ];
     };
 
     users = {
diff --git a/modules/by-name/st/stalwart-mail/module.nix b/modules/by-name/st/stalwart-mail/module.nix
index 7bd985f..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-free" {};
+    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/modules/by-name/ta/taskchampion-sync/module.nix b/modules/by-name/ta/taskchampion-sync/module.nix
index 1870186..a722883 100644
--- a/modules/by-name/ta/taskchampion-sync/module.nix
+++ b/modules/by-name/ta/taskchampion-sync/module.nix
@@ -8,6 +8,12 @@
 in {
   options.vhack.taskchampion-sync = {
     enable = lib.mkEnableOption "taskchampion-sync";
+
+    fqdn = lib.mkOption {
+      description = "The fully qualified domain name of this instance.";
+      type = lib.types.str;
+      example = "task-sync.tw.online";
+    };
   };
 
   config = lib.mkIf cfg.enable {
@@ -16,19 +22,32 @@ in {
       groups.taskchampion.gid = config.vhack.constants.ids.uids.taskchampion;
     };
 
-    vhack.persist.directories = [
-      {
-        directory = dataDirectory;
-        user = "taskchampion";
-        group = "taskchampion";
-        mode = "0700";
-      }
-    ];
+    vhack = {
+      persist.directories = [
+        {
+          directory = dataDirectory;
+          user = "taskchampion";
+          group = "taskchampion";
+          mode = "0700";
+        }
+      ];
+      nginx.enable = true;
+    };
+
+    services = {
+      taskchampion-sync-server = {
+        enable = true;
+        dataDir = dataDirectory;
+      };
 
-    services.taskchampion-sync-server = {
-      enable = true;
-      openFirewall = true;
-      dataDir = dataDirectory;
+      nginx.virtualHosts."${cfg.fqdn}" = {
+        locations."/" = {
+          proxyPass = "http://127.0.0.1:${toString config.services.taskchampion-sync-server.port}";
+          recommendedProxySettings = true;
+        };
+        enableACME = true;
+        forceSSL = true;
+      };
     };
   };
 }
diff --git a/modules/by-name/us/users/module.nix b/modules/by-name/us/users/module.nix
index a197b13..6011204 100644
--- a/modules/by-name/us/users/module.nix
+++ b/modules/by-name/us/users/module.nix
@@ -27,20 +27,22 @@
     };
   };
 
-  extraUsers = lib.listToAttrs (builtins.map mkUser [
-    {
-      name = "soispha";
-      password = "$y$jFT$3.8XmUyukZvpExMUxDZkI.$IVrJgm8ysNDF/0vDD2kF6w73ozXgr1LMVRNN4Bq7pv1";
-      sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIME4ZVa+IoZf6T3U08JG93i6QIAJ4amm7mkBzO14JSkz cardno:000F_18F83532";
-      uid = 1000;
-    }
-    {
-      name = "sils";
-      password = "$y$jFT$KpFnahVCE9JbE.5P3us8o.$ZzSxCusWqe3sL7b6DLgOXNNUf114tiiptM6T8lDxtKC";
-      sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAe4o1PM6VasT3KZNl5NYvgkkBrPOg36dqsywd10FztS openpgp:0x21D20D6A";
-      uid = 1001;
-    }
-  ]);
+  extraUsers = lib.listToAttrs (
+    builtins.map mkUser [
+      {
+        name = "soispha";
+        password = "$y$jFT$3.8XmUyukZvpExMUxDZkI.$IVrJgm8ysNDF/0vDD2kF6w73ozXgr1LMVRNN4Bq7pv1";
+        sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIME4ZVa+IoZf6T3U08JG93i6QIAJ4amm7mkBzO14JSkz cardno:000F_18F83532";
+        uid = 1000;
+      }
+      {
+        name = "sils";
+        password = "$y$jFT$KpFnahVCE9JbE.5P3us8o.$ZzSxCusWqe3sL7b6DLgOXNNUf114tiiptM6T8lDxtKC";
+        sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILn7Oumr5IYtTTIKRFvDnofGXXiDLBQE9jVF+7UE+4G5 vhack.eu";
+        uid = 1001;
+      }
+    ]
+  );
 in {
   options.vhack.users = {
     enable = lib.mkEnableOption "user setup";