Personal-use NixOS configuration
at main 236 lines 4.5 kB view raw
1{ 2 domain, 3 email, 4 ssl, 5}: 6 7let 8 subdomain = "mx.${domain}"; 9 10 tlsModule = import ./mta-sts.nix { 11 inherit domain ssl; 12 }; 13 14 autoconfigModule = import ./autoconfig.nix { 15 inherit domain; 16 17 hosts = [ 18 { 19 name = "autoconfig.${domain}"; 20 21 inherit ssl; 22 } 23 ]; 24 }; 25in 26{ 27 imports = [ 28 ../databases/postgresql.nix 29 ./rspamd.nix 30 31 tlsModule 32 autoconfigModule 33 ]; 34 35 services.maddy = { 36 enable = true; 37 38 primaryDomain = subdomain; 39 40 localDomains = [ 41 "$(hostname)" 42 ]; 43 44 tls = { 45 loader = "acme"; 46 extraConfig = '' 47 email ${email} 48 agreed 49 50 hostname ${subdomain} 51 challenge dns-01 52 53 dns cloudflare { 54 api_token "{env:CF_API_TOKEN}" 55 } 56 ''; 57 }; 58 59 config = '' 60 auth.pass_table local_authdb { 61 table sql_table { 62 driver postgres 63 dsn "host=/run/postgresql dbname=maddy user=maddy" 64 table_name passwords 65 } 66 } 67 68 storage.imapsql local_mailboxes { 69 driver postgres 70 dsn "host=/run/postgresql dbname=maddy user=maddy" 71 } 72 73 table.chain local_rewrites { 74 optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3" 75 76 optional_step static { 77 entry postmaster postmaster@$(primary_domain) 78 } 79 80 optional_step file /etc/maddy/aliases 81 } 82 83 msgpipeline local_routing { 84 check { 85 rspamd { 86 api_path unix:/run/rspamd/rspamd.sock 87 } 88 } 89 90 destination postmaster $(local_domains) { 91 modify { 92 replace_rcpt &local_rewrites 93 } 94 95 deliver_to &local_mailboxes 96 } 97 98 default_destination { 99 reject 550 5.1.1 "User doesn't exist" 100 } 101 } 102 103 smtp tcp://0.0.0.0:25 { 104 limits { 105 all rate 25 1s 106 all concurrency 10 107 } 108 109 dmarc yes 110 max_message_size 25M 111 check { 112 require_mx_record 113 dkim 114 spf 115 } 116 117 source $(local_domains) { 118 reject 501 5.1.8 "Use Submission for outgoing SMTP" 119 } 120 121 default_source { 122 destination postmaster $(local_domains) { 123 deliver_to &local_routing 124 } 125 126 default_destination { 127 reject 550 5.1.1 "User doesn't exist" 128 } 129 } 130 } 131 132 submission tls://0.0.0.0:465 tcp://0.0.0.0:587 { 133 limits { 134 all rate 25 1s 135 } 136 137 auth &local_authdb 138 139 source $(local_domains) { 140 check { 141 authorize_sender { 142 prepare_email &local_rewrites 143 user_to_email identity 144 } 145 } 146 147 destination postmaster $(local_domains) { 148 deliver_to &local_routing 149 } 150 151 default_destination { 152 modify { 153 dkim $(primary_domain) $(local_domains) default 154 } 155 156 deliver_to &remote_queue 157 } 158 } 159 160 default_source { 161 reject 501 5.1.8 "Non-local sender domain" 162 } 163 } 164 165 imap tls://0.0.0.0:993 tcp://0.0.0.0:143 { 166 auth &local_authdb 167 storage &local_mailboxes 168 } 169 170 target.remote outbound_delivery { 171 limits { 172 destination rate 25 1s 173 destination concurrency 10 174 } 175 176 mx_auth { 177 dane 178 mtasts { 179 cache ram 180 } 181 local_policy { 182 min_tls_level encrypted 183 min_mx_level none 184 } 185 } 186 } 187 188 target.queue remote_queue { 189 target &outbound_delivery 190 191 autogenerated_msg_domain $(primary_domain) 192 193 bounce { 194 destination postmaster $(local_domains) { 195 deliver_to &local_routing 196 } 197 198 default_destination { 199 reject 550 5.0.0 "Refusing to send DSNs to non-local addresses" 200 } 201 } 202 } 203 ''; 204 }; 205 206 networking.firewall.allowedTCPPorts = [ 207 25 208 587 209 465 210 143 211 993 212 ]; 213 214 # Ensure creation of PostgreSQL database 215 services.postgresql = { 216 ensureUsers = [ 217 { 218 name = "maddy"; 219 ensureDBOwnership = true; 220 } 221 ]; 222 223 ensureDatabases = [ "maddy" ]; 224 }; 225 226 # Configure rspamd 227 services.rspamd = { 228 locals."dkim_signing.conf".text = '' 229 selector = "default"; 230 domain = "${subdomain}"; 231 path = "/var/lib/maddy/dkim_keys/$domain_$selector.key"; 232 ''; 233 }; 234 235 systemd.services.rspamd.serviceConfig.SupplementaryGroups = [ "maddy" ]; 236}