My Nix Configuration
1{ 2 config, 3 lib, 4 self, 5 ... 6}: 7let 8 d = self.lib.data.mail; 9 cfg = config.services.stalwart-mail; 10 sec = config.age.secrets; 11 creds = config.services.stalwart-mail.credentials; 12 credsDir = "/run/credentials/stalwart-mail.service"; 13 certDir = config.security.acme.certs."pyroxdev-mail".directory; 14 isAuthenticated = d: { 15 "if" = "!is_empty(authenticated_as)"; 16 "then" = d; 17 }; 18 otherwise = d: { 19 "else" = d; 20 }; 21 ifThen = f: d: { 22 "if" = f; 23 "then" = d; 24 }; 25 smSecret = { 26 owner = "stalwart-mail"; 27 group = "stalwart-mail"; 28 }; 29in 30{ 31 services.stalwart-mail = { 32 credentials = { 33 cert = "${certDir}/cert.pem"; 34 key = "${certDir}/key.pem"; 35 }; 36 enable = true; 37 dataDir = "/var/lib/stalwart"; 38 settings = { 39 tracer.stdout.level = "info"; 40 authentication.fallback-admin = { 41 user = "fallback"; 42 secret = "%{file:${sec.stalwart-fallback-admin-pw.path}}%"; 43 }; 44 config = { 45 local-keys = [ 46 "asn.*" 47 "auth.*" 48 "authentication.*" 49 "auto-ban.*" 50 "calendar.*" 51 "certificate.*" 52 "changes.*" 53 "cluster.*" 54 "config.*" 55 "contacts.*" 56 "directory.*" 57 "http.*" 58 "imap.*" 59 "jmap.*" 60 "queue.*" 61 "report.*" 62 "resolver.*" 63 "server.*" 64 "session.*" 65 "signature.*" 66 "storage.*" 67 "store.*" 68 "tracer.*" 69 "webadmin.*" 70 "form.*" 71 "email.*" 72 "spam-filter.*" 73 ]; 74 }; 75 certificate = { 76 default = { 77 default = true; 78 cert = "%{file:${credsDir}/cert}%"; 79 private-key = "%{file:${credsDir}/key}%"; 80 subjects = [ 81 "dav.pyrox.dev" 82 "mail.pyrox.dev" 83 "mta-sts.pyrox.dev" 84 "autoconfig.pyrox.dev" 85 "autodiscover.pyrox.dev" 86 ]; 87 }; 88 }; 89 server = import ./server.nix { inherit d; }; 90 # Use NixOS-generated certs now, since stalwart can't do it on its own 91 # (DeSec API Errors abound) 92 # acme = import ./acme.nix { inherit cfg sec; }; 93 # HTTP Configuration 94 # https://stalw.art/docs/http/overview 95 http = { 96 url = "'https://${d.extUrl}'"; 97 hsts = true; 98 rate-limit = { 99 account = "10000/1m"; 100 }; 101 }; 102 # Disable HTTP Forms submission 103 # https://stalw.art/docs/http/form-submission 104 form.enable = false; 105 # DKIM Signatures 106 signature = import ./signature.nix { inherit sec; }; 107 # Storage Settings 108 # https://stalw.art/docs/storage/overview 109 store = { 110 data = { 111 type = "rocksdb"; 112 path = "${cfg.dataDir}/db"; 113 purge.frequency = "0 3 *"; 114 }; 115 blob = { 116 type = "fs"; 117 path = "${cfg.dataDir}/blobs"; 118 depth = 2; 119 compression = "lz4"; 120 purge.frequency = "0 4 *"; 121 }; 122 db.path = "${cfg.dataDir}/db2"; 123 }; 124 storage = { 125 data = "data"; 126 blob = "blob"; 127 fts = "data"; 128 lookup = "data"; 129 directory = "default"; 130 }; 131 directory = { 132 default = { 133 type = "internal"; 134 store = "data"; 135 }; 136 }; 137 # ASN/GeoIP Lookups 138 # https://stalw.art/docs/server/asn 139 asn = { 140 type = "dns"; 141 separator = "|"; 142 zone.ipv4 = "origin.asn.cymru.com"; 143 zone.ipv6 = "origin6.asn.cymru.com"; 144 index.asn = 0; 145 index.asn-name = 1; 146 index.country = 2; 147 }; 148 auto-ban = import ./auto-ban.nix; 149 # JMAP Settings 150 # https://stalw.art/docs/email/jmap 151 jmap = { 152 mailbox.max-depth = 10; 153 mailbox.max-name-length = 255; 154 # 50 MB 155 email.max-attachment-size = 50 * 1000 * 1000; 156 # 75 MB 157 email.max-size = 75 * 1000 * 1000; 158 email.parse.max-items = 10; 159 }; 160 imap = import ./imap.nix; 161 # Maintainance 162 # https://stalw.art/docs/email/maintenance 163 email.auto-expunge = "180d"; 164 changes.max-history = 10000; 165 session = import ./session.nix { inherit isAuthenticated otherwise ifThen; }; 166 queue = import ./queue.nix { inherit d ifThen otherwise; }; 167 # DNS Settings 168 # https://stalw.art/docs/mta/outbound/dns 169 resolver = { 170 custom = [ 171 "tls://dns11.quad9.net" 172 "tcp://1.1.1.1" 173 ]; 174 concurrency = 2; 175 preserve-intermediates = true; 176 timeout = "5s"; 177 attempts = 3; 178 edns = true; 179 }; 180 report = import ./report.nix { inherit d; }; 181 calendar = import ./calendar.nix; 182 # Authentication 183 auth = import ./auth.nix { inherit ifThen otherwise; }; 184 # Contacts 185 # https://stalw.art/docs/collaboration/contact 186 contacts = { 187 # 512 KiB 188 max-size = 524288; 189 default.href-name = "default"; 190 default.display-name = "Contacts"; 191 }; 192 # Spam Filtering 193 # https://stalw.art/docs/spamfilter/overview 194 spam-filter = { 195 card-is-ham = true; 196 }; 197 }; 198 }; 199 systemd.services.stalwart-mail.serviceConfig = { 200 Restart = lib.mkForce "always"; 201 RestartSec = lib.mkForce 1; 202 }; 203 age.secrets = { 204 stalwart-secret-rsa = smSecret // { 205 file = ../../secrets/stalwart-secret-rsa.age; 206 }; 207 stalwart-secret-ed25519 = smSecret // { 208 file = ../../secrets/stalwart-secret-ed25519.age; 209 }; 210 stalwart-desec-token = smSecret // { 211 file = ../../secrets/stalwart-desec-token.age; 212 }; 213 stalwart-fallback-admin-pw = smSecret // { 214 file = ../../secrets/stalwart-fallback-admin-pw.age; 215 }; 216 }; 217}