diff options
Diffstat (limited to 'nixos/modules/services/mail')
-rw-r--r-- | nixos/modules/services/mail/mailman.nix | 11 | ||||
-rw-r--r-- | nixos/modules/services/mail/roundcube.nix | 7 | ||||
-rw-r--r-- | nixos/modules/services/mail/stalwart-mail.nix | 158 |
3 files changed, 104 insertions, 72 deletions
diff --git a/nixos/modules/services/mail/mailman.nix b/nixos/modules/services/mail/mailman.nix index 7e7ca7e4060e..180c9800d734 100644 --- a/nixos/modules/services/mail/mailman.nix +++ b/nixos/modules/services/mail/mailman.nix @@ -534,14 +534,11 @@ in { hyperkittyApiKey=$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 64) secretKey=$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 64) - mailmanWebCfgTmp=$(mktemp) - jq -n '.MAILMAN_ARCHIVER_KEY=$archiver_key | .SECRET_KEY=$secret_key' \ + install -m 0440 -o root -g mailman \ + <(jq -n '.MAILMAN_ARCHIVER_KEY=$archiver_key | .SECRET_KEY=$secret_key' \ --arg archiver_key "$hyperkittyApiKey" \ - --arg secret_key "$secretKey" \ - >"$mailmanWebCfgTmp" - chown root:mailman "$mailmanWebCfgTmp" - chmod 440 "$mailmanWebCfgTmp" - mv -n "$mailmanWebCfgTmp" "$mailmanWebCfg" + --arg secret_key "$secretKey") \ + "$mailmanWebCfg" fi hyperkittyApiKey="$(jq -r .MAILMAN_ARCHIVER_KEY "$mailmanWebCfg")" diff --git a/nixos/modules/services/mail/roundcube.nix b/nixos/modules/services/mail/roundcube.nix index 4499532ace89..78f627d33e2d 100644 --- a/nixos/modules/services/mail/roundcube.nix +++ b/nixos/modules/services/mail/roundcube.nix @@ -7,7 +7,7 @@ let fpm = config.services.phpfpm.pools.roundcube; localDB = cfg.database.host == "localhost"; user = cfg.database.username; - phpWithPspell = pkgs.php81.withExtensions ({ enabled, all }: [ all.pspell ] ++ enabled); + phpWithPspell = pkgs.php83.withExtensions ({ enabled, all }: [ all.pspell ] ++ enabled); in { options.services.roundcube = { @@ -247,14 +247,15 @@ in (mkIf (cfg.database.host == "localhost") { requires = [ "postgresql.service" ]; after = [ "postgresql.service" ]; - path = [ config.services.postgresql.package ]; }) { wants = [ "network-online.target" ]; after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; + + path = [ config.services.postgresql.package ]; script = let - psql = "${lib.optionalString (!localDB) "PGPASSFILE=${cfg.database.passwordFile}"} ${pkgs.postgresql}/bin/psql ${lib.optionalString (!localDB) "-h ${cfg.database.host} -U ${cfg.database.username} "} ${cfg.database.dbname}"; + psql = "${lib.optionalString (!localDB) "PGPASSFILE=${cfg.database.passwordFile}"} psql ${lib.optionalString (!localDB) "-h ${cfg.database.host} -U ${cfg.database.username} "} ${cfg.database.dbname}"; in '' version="$(${psql} -t <<< "select value from system where name = 'roundcube-version';" || true)" diff --git a/nixos/modules/services/mail/stalwart-mail.nix b/nixos/modules/services/mail/stalwart-mail.nix index 9cc919fd117d..ed3c5389354c 100644 --- a/nixos/modules/services/mail/stalwart-mail.nix +++ b/nixos/modules/services/mail/stalwart-mail.nix @@ -7,10 +7,12 @@ let configFormat = pkgs.formats.toml { }; configFile = configFormat.generate "stalwart-mail.toml" cfg.settings; dataDir = "/var/lib/stalwart-mail"; + useLegacyStorage = versionOlder config.system.stateVersion "24.11"; in { options.services.stalwart-mail = { enable = mkEnableOption "the Stalwart all-in-one email server"; + package = mkPackageOption pkgs "stalwart-mail" { }; settings = mkOption { @@ -26,78 +28,110 @@ in { }; config = mkIf cfg.enable { + # Default config: all local services.stalwart-mail.settings = { - global.tracing.method = mkDefault "stdout"; - global.tracing.level = mkDefault "info"; + tracer.stdout = { + type = mkDefault "stdout"; + level = mkDefault "info"; + ansi = mkDefault false; # no colour markers to journald + enable = mkDefault true; + }; queue.path = mkDefault "${dataDir}/queue"; report.path = mkDefault "${dataDir}/reports"; - store.db.type = mkDefault "sqlite"; - store.db.path = mkDefault "${dataDir}/data/index.sqlite3"; - store.blob.type = mkDefault "fs"; - store.blob.path = mkDefault "${dataDir}/data/blobs"; + store = if useLegacyStorage then { + # structured data in SQLite, blobs on filesystem + db.type = mkDefault "sqlite"; + db.path = mkDefault "${dataDir}/data/index.sqlite3"; + fs.type = mkDefault "fs"; + fs.path = mkDefault "${dataDir}/data/blobs"; + } else { + # everything in RocksDB + db.type = mkDefault "rocksdb"; + db.path = mkDefault "${dataDir}/db"; + db.compression = mkDefault "lz4"; + }; storage.data = mkDefault "db"; storage.fts = mkDefault "db"; - storage.blob = mkDefault "blob"; + storage.lookup = mkDefault "db"; + storage.blob = mkDefault (if useLegacyStorage then "fs" else "db"); + directory.internal.type = mkDefault "internal"; + directory.internal.store = mkDefault "db"; + storage.directory = mkDefault "internal"; resolver.type = mkDefault "system"; - resolver.public-suffix = mkDefault ["https://publicsuffix.org/list/public_suffix_list.dat"]; + resolver.public-suffix = lib.mkDefault [ + "file://${pkgs.publicsuffix-list}/share/publicsuffix/public_suffix_list.dat" + ]; + }; + + # This service stores a potentially large amount of data. + # Running it as a dynamic user would force chown to be run everytime the + # service is restarted on a potentially large number of files. + # That would cause unnecessary and unwanted delays. + users = { + groups.stalwart-mail = { }; + users.stalwart-mail = { + isSystemUser = true; + group = "stalwart-mail"; + }; }; - systemd.services.stalwart-mail = { - wantedBy = [ "multi-user.target" ]; - after = [ "local-fs.target" "network.target" ]; + systemd = { + packages = [ cfg.package ]; + services.stalwart-mail = { + wantedBy = [ "multi-user.target" ]; + after = [ "local-fs.target" "network.target" ]; - preStart = '' - mkdir -p ${dataDir}/{queue,reports,data/blobs} - ''; + preStart = if useLegacyStorage then '' + mkdir -p ${dataDir}/{queue,reports,data/blobs} + '' else '' + mkdir -p ${dataDir}/{queue,reports,db} + ''; + + serviceConfig = { + ExecStart = [ + "" + "${cfg.package}/bin/stalwart-mail --config=${configFile}" + ]; + + StandardOutput = "journal"; + StandardError = "journal"; + + StateDirectory = "stalwart-mail"; + + # Bind standard privileged ports + AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; + CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; - serviceConfig = { - ExecStart = - "${cfg.package}/bin/stalwart-mail --config=${configFile}"; - - # Base from template resources/systemd/stalwart-mail.service - Type = "simple"; - LimitNOFILE = 65536; - KillMode = "process"; - KillSignal = "SIGINT"; - Restart = "on-failure"; - RestartSec = 5; - StandardOutput = "journal"; - StandardError = "journal"; - SyslogIdentifier = "stalwart-mail"; - - DynamicUser = true; - User = "stalwart-mail"; - StateDirectory = "stalwart-mail"; - - # Bind standard privileged ports - AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; - CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; - - # Hardening - DeviceAllow = [ "" ]; - LockPersonality = true; - MemoryDenyWriteExecute = true; - PrivateDevices = true; - PrivateUsers = false; # incompatible with CAP_NET_BIND_SERVICE - ProcSubset = "pid"; - PrivateTmp = true; - ProtectClock = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectProc = "invisible"; - ProtectSystem = "strict"; - RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - SystemCallArchitectures = "native"; - SystemCallFilter = [ "@system-service" "~@privileged" ]; - UMask = "0077"; + # Hardening + DeviceAllow = [ "" ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + PrivateDevices = true; + PrivateUsers = false; # incompatible with CAP_NET_BIND_SERVICE + ProcSubset = "pid"; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@privileged" ]; + UMask = "0077"; + }; + unitConfig.ConditionPathExists = [ + "" + "${configFile}" + ]; }; }; @@ -106,6 +140,6 @@ in { }; meta = { - maintainers = with maintainers; [ happysalada pacien ]; + maintainers = with maintainers; [ happysalada pacien onny ]; }; } |