about summary refs log tree commit diff stats
path: root/modules/by-name/st/stalwart-mail/module.nix
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-03-04 20:22:08 +0100
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-03-09 13:44:31 +0100
commitd86f0cb1cdd1d3dd50e9d2a27b42895028044fdf (patch)
treebbcc86a3ac100c5b124f2f453fc1f6b5513af018 /modules/by-name/st/stalwart-mail/module.nix
parentmodules/stalwart-mail: Select DKIM keys per-domain (diff)
downloadnixos-server-d86f0cb1cdd1d3dd50e9d2a27b42895028044fdf.zip
modules/stalwart-mail: Include full systemd service and set correct dependencies
This also starts `nginx` so that we can complete http-01 acme
challenges.
Diffstat (limited to 'modules/by-name/st/stalwart-mail/module.nix')
-rw-r--r--modules/by-name/st/stalwart-mail/module.nix130
1 files changed, 89 insertions, 41 deletions
diff --git a/modules/by-name/st/stalwart-mail/module.nix b/modules/by-name/st/stalwart-mail/module.nix
index 3ef7d85..eb2703c 100644
--- a/modules/by-name/st/stalwart-mail/module.nix
+++ b/modules/by-name/st/stalwart-mail/module.nix
@@ -156,13 +156,59 @@ in {
       }
     ];
 
-    services.stalwart-mail = {
-      # NOTE(@bpeetz): We do not use the nixos service, as it comes with too much
-      # bothersome default configuration and not really any useful config.
-      # However, this decision could obviously be reverse in the future. <2025-02-08>
-      enable = false;
-      inherit (cfg) package;
-      # dataDir = cfg.dataDirectory;
+    vhack.nginx.enable = true;
+    services = {
+      stalwart-mail = {
+        # NOTE(@bpeetz): We do not use the NixOS service, as it comes with too much
+        # bothersome default configuration and not really any useful configuration.
+        # However, this decision could obviously be reversed in the future. <2025-02-08>
+        enable = false;
+        inherit (cfg) package;
+        # dataDir = cfg.dataDirectory;
+      };
+
+      # FIXME(@bpeetz): This is currently needed for a successful acme http-01 challenge.
+      # We could also use the DNS challenge. <2025-03-01>
+      nginx.virtualHosts."${cfg.fqdn}" = {
+        enableACME = false;
+        extraConfig =
+          # This is copied directly from the nixos nginx module.
+          # Rule for legitimate ACME Challenge requests (like /.well-known/acme-challenge/xxxxxxxxx)
+          # We use ^~ here, so that we don't check any regexes (which could
+          # otherwise easily override this intended match accidentally).
+          ''
+            location ^~ /.well-known/acme-challenge/ {
+              root ${config.security.acme.certs.${cfg.fqdn}.webroot};
+              auth_basic off;
+              auth_request off;
+            }
+          '';
+      };
+
+      redis = {
+        servers = {
+          "stalwart-mail" = {
+            enable = true;
+
+            user = "stalwart-mail";
+
+            # 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";
+            };
+          };
+        };
+      };
     };
     security.acme.certs = {
       "${cfg.fqdn}" = {
@@ -202,31 +248,6 @@ in {
       }
     ];
 
-    services.redis = {
-      servers = {
-        "stalwart-mail" = {
-          enable = true;
-
-          user = "stalwart-mail";
-
-          # 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";
-          };
-        };
-      };
-    };
-
     # This service stores a potentially large amount of data.
     # Running it as a dynamic user would force chown to be run every time the
     # service is restarted on a potentially large number of files.
@@ -244,13 +265,31 @@ in {
     ];
 
     systemd = {
-      packages = [cfg.package];
       services.stalwart-mail = {
         wantedBy = ["multi-user.target"];
+        requires = [
+          "redis-stalwart-mail.service"
+          "network-online.target"
+          "acme-${cfg.fqdn}.service"
+        ];
         after = [
           "local-fs.target"
           "network.target"
+          "network-online.target"
+          "redis-stalwart-mail.service"
+          "acme-${cfg.fqdn}.service"
+        ];
+        conflicts = [
+          "postfix.service"
+          "sendmail.service"
+          "exim4.service"
         ];
+        description = "Stalwart Mail Server";
+
+        environment = {
+          SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
+          NIX_SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
+        };
 
         preStart = let
           esa = lib.strings.escapeShellArg;
@@ -271,10 +310,18 @@ in {
           + (builtins.concatStringsSep "\n" storageDirectories);
 
         serviceConfig = {
-          ExecStart = [
-            ""
-            "${cfg.package}/bin/stalwart-mail --config=$CACHE_DIRECTORY/mutable_config_file.toml"
-          ];
+          ExecStart = pkgs.writers.writeDash "start-stalwart-mail" ''
+            ${lib.getExe cfg.package} --config="$CACHE_DIRECTORY/mutable_config_file.toml"
+          '';
+
+          Restart = "on-failure";
+          RestartSec = 5;
+
+          KillMode = "process";
+          KillSignal = "SIGINT";
+
+          Type = "simple";
+          LimitNOFILE = 65536;
 
           StandardOutput = "journal";
           StandardError = "journal";
@@ -285,6 +332,11 @@ in {
           CacheDirectory = "stalwart-mail";
           StateDirectory = "stalwart-mail";
 
+          User = "stalwart-mail";
+          Group = "stalwart-mail";
+
+          SyslogIdentifier = "stalwart-mail";
+
           # Bind standard privileged ports
           AmbientCapabilities = ["CAP_NET_BIND_SERVICE"];
           CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];
@@ -321,10 +373,6 @@ in {
           ];
           UMask = "0077";
         };
-        unitConfig.ConditionPathExists = [
-          ""
-          "${configFile}"
-        ];
       };
     };