This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

machines.neoprism: replace exim-smarthost with simple-nixos-mailserver

IMAPS, SMTP submission, sieve filtering, DKIM, full-text search.
Remove dead code internet-gateway.nix and hackerfleet exim router.
Add mail and DKIM dirs to borg backup.

+322 -62
+105
flake.lock
··· 1 1 { 2 2 "nodes": { 3 + "blobs": { 4 + "flake": false, 5 + "locked": { 6 + "lastModified": 1604995301, 7 + "narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=", 8 + "owner": "simple-nixos-mailserver", 9 + "repo": "blobs", 10 + "rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265", 11 + "type": "gitlab" 12 + }, 13 + "original": { 14 + "owner": "simple-nixos-mailserver", 15 + "repo": "blobs", 16 + "type": "gitlab" 17 + } 18 + }, 3 19 "blueprint": { 4 20 "inputs": { 5 21 "nixpkgs": [ ··· 120 136 "type": "github" 121 137 } 122 138 }, 139 + "flake-compat": { 140 + "flake": false, 141 + "locked": { 142 + "lastModified": 1767039857, 143 + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", 144 + "owner": "NixOS", 145 + "repo": "flake-compat", 146 + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", 147 + "type": "github" 148 + }, 149 + "original": { 150 + "owner": "NixOS", 151 + "repo": "flake-compat", 152 + "type": "github" 153 + } 154 + }, 123 155 "flake-parts": { 124 156 "inputs": { 125 157 "nixpkgs-lib": [ ··· 234 266 "original": { 235 267 "owner": "numtide", 236 268 "repo": "flake-utils", 269 + "type": "github" 270 + } 271 + }, 272 + "git-hooks": { 273 + "inputs": { 274 + "flake-compat": [ 275 + "nixos-mailserver", 276 + "flake-compat" 277 + ], 278 + "gitignore": "gitignore", 279 + "nixpkgs": [ 280 + "nixos-mailserver", 281 + "nixpkgs" 282 + ] 283 + }, 284 + "locked": { 285 + "lastModified": 1769939035, 286 + "narHash": "sha256-Fok2AmefgVA0+eprw2NDwqKkPGEI5wvR+twiZagBvrg=", 287 + "owner": "cachix", 288 + "repo": "git-hooks.nix", 289 + "rev": "a8ca480175326551d6c4121498316261cbb5b260", 290 + "type": "github" 291 + }, 292 + "original": { 293 + "owner": "cachix", 294 + "repo": "git-hooks.nix", 295 + "type": "github" 296 + } 297 + }, 298 + "gitignore": { 299 + "inputs": { 300 + "nixpkgs": [ 301 + "nixos-mailserver", 302 + "git-hooks", 303 + "nixpkgs" 304 + ] 305 + }, 306 + "locked": { 307 + "lastModified": 1709087332, 308 + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", 309 + "owner": "hercules-ci", 310 + "repo": "gitignore.nix", 311 + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", 312 + "type": "github" 313 + }, 314 + "original": { 315 + "owner": "hercules-ci", 316 + "repo": "gitignore.nix", 237 317 "type": "github" 238 318 } 239 319 }, ··· 453 533 "type": "github" 454 534 } 455 535 }, 536 + "nixos-mailserver": { 537 + "inputs": { 538 + "blobs": "blobs", 539 + "flake-compat": "flake-compat", 540 + "git-hooks": "git-hooks", 541 + "nixpkgs": [ 542 + "nixpkgs" 543 + ] 544 + }, 545 + "locked": { 546 + "lastModified": 1772722317, 547 + "narHash": "sha256-y47/GkUkr/aKN8oBx3wLWgpIWnTY+x2pJ2mxD1AMeEg=", 548 + "owner": "simple-nixos-mailserver", 549 + "repo": "nixos-mailserver", 550 + "rev": "3938a7518aa109697983103139cb6ea99d897af5", 551 + "type": "gitlab" 552 + }, 553 + "original": { 554 + "owner": "simple-nixos-mailserver", 555 + "ref": "master", 556 + "repo": "nixos-mailserver", 557 + "type": "gitlab" 558 + } 559 + }, 456 560 "nixpkgs": { 457 561 "locked": { 458 562 "lastModified": 1772433332, ··· 547 651 "nix-rosetta-builder": "nix-rosetta-builder", 548 652 "nixos-facter": "nixos-facter", 549 653 "nixos-hardware": "nixos-hardware", 654 + "nixos-mailserver": "nixos-mailserver", 550 655 "nixpkgs": "nixpkgs", 551 656 "nixvim": "nixvim", 552 657 "opencrow": "opencrow",
+3
flake.nix
··· 72 72 73 73 opencrow.url = "github:Lassulus/opencrow/tool_n_stop"; 74 74 opencrow.inputs.nixpkgs.follows = "nixpkgs"; 75 + 76 + nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver/master"; 77 + nixos-mailserver.inputs.nixpkgs.follows = "nixpkgs"; 75 78 }; 76 79 77 80 outputs =
+211
2configs/mailserver.nix
··· 1 + { 2 + self, 3 + config, 4 + lib, 5 + pkgs, 6 + ... 7 + }: 8 + let 9 + relayHosts = map (host: host.nets.retiolum.ip6.addr) [ 10 + config.krebs.hosts.aergia 11 + config.krebs.hosts.ignavia 12 + config.krebs.hosts.coaxmetal 13 + config.krebs.hosts.green 14 + config.krebs.hosts.mors 15 + ]; 16 + 17 + mynetworks = map (ip: "[${ip}]") relayHosts; 18 + in 19 + { 20 + imports = [ 21 + self.inputs.nixos-mailserver.nixosModules.default 22 + ]; 23 + 24 + mailserver = { 25 + enable = true; 26 + fqdn = "mail.lassul.us"; 27 + domains = [ "lassul.us" ]; 28 + 29 + loginAccounts = { 30 + "lass@lassul.us" = { 31 + hashedPasswordFile = 32 + config.clan.core.vars.generators.mailserver-lass.files."lass-mail-password-hash".path; 33 + aliases = [ 34 + "postmaster@lassul.us" 35 + "root@lassul.us" 36 + "abuse@lassul.us" 37 + "hostmaster@lassul.us" 38 + "webmaster@lassul.us" 39 + "security@lassul.us" 40 + "noc@lassul.us" 41 + "mailer-daemon@lassul.us" 42 + "nobody@lassul.us" 43 + "lassulus@lassul.us" 44 + ]; 45 + catchAll = [ "lassul.us" ]; 46 + sieveScript = '' 47 + require ["fileinto", "mailbox"]; 48 + 49 + # GitHub — sort by repo from List-Id header 50 + if header :matches "List-Id" "*.github.com" { 51 + if header :contains "List-Id" "nixpkgs" { fileinto :create "GitHub.nixpkgs"; } 52 + elsif header :contains "List-Id" "disko" { fileinto :create "GitHub.disko"; } 53 + elsif header :contains "List-Id" "clan-core" { fileinto :create "GitHub.clan-core"; } 54 + elsif header :contains "List-Id" "data-mesher" { fileinto :create "GitHub.data-mesher"; } 55 + elsif header :contains "List-Id" "foundation" { fileinto :create "GitHub.foundation"; } 56 + elsif header :contains "List-Id" "nix." { fileinto :create "GitHub.nix"; } 57 + elsif header :contains "List-Id" "nixos-wiki" { fileinto :create "GitHub.nixos-wiki"; } 58 + elsif header :contains "List-Id" "nixos-homepage" { fileinto :create "GitHub.nixos-homepage"; } 59 + else { fileinto :create "GitHub.other"; } 60 + stop; 61 + } 62 + 63 + # Gitea (clan) 64 + if anyof ( 65 + header :matches "X-Gitea-*" "*", 66 + address :domain "From" "clan.lol" 67 + ) { 68 + fileinto :create "GitHub.clan"; 69 + stop; 70 + } 71 + 72 + # Mailing lists — sort by List-Id 73 + if exists "List-Id" { 74 + if header :contains "List-Id" "vorstand.c-base" { fileinto :create "Lists.c-base-vorstand"; } 75 + elsif header :contains "List-Id" "c-base" { fileinto :create "Lists.c-base"; } 76 + elsif header :contains "List-Id" "afra" { fileinto :create "Lists.afra"; } 77 + elsif header :contains "List-Id" "soundlab" { fileinto :create "Lists.soundlab"; } 78 + elsif header :contains "List-Id" "nixos" { fileinto :create "Lists.nixos"; } 79 + elsif header :contains "List-Id" "shack" { fileinto :create "Lists.shack"; } 80 + elsif header :contains "List-Id" "dezentrale" { fileinto :create "Lists.dezentrale"; } 81 + elsif header :contains "List-Id" "dn42" { fileinto :create "Lists.dn42"; } 82 + elsif header :contains "List-Id" "tinc" { fileinto :create "Lists.tinc"; } 83 + elsif header :contains "List-Id" "wireguard" { fileinto :create "Lists.wireguard"; } 84 + elsif header :contains "List-Id" "retiolum" { fileinto :create "Lists.retiolum"; } 85 + else { fileinto :create "Lists.other"; } 86 + stop; 87 + } 88 + 89 + # Billing/receipts 90 + if anyof ( 91 + address :domain "From" "paypal.de", 92 + address :domain "From" "paypal.com", 93 + address :domain "From" "steuerberaten.de", 94 + address :domain "From" "patreon.com", 95 + address :domain "From" "dhl.de", 96 + address :domain "From" "eloop.app", 97 + header :contains "Subject" "Rechnung", 98 + header :contains "Subject" "Invoice", 99 + header :contains "Subject" "receipt" 100 + ) { 101 + fileinto :create "Billing"; 102 + stop; 103 + } 104 + 105 + # Newsletters (has unsubscribe but no List-Id) 106 + if allof ( 107 + header :contains "List-Unsubscribe" "http", 108 + not exists "List-Id" 109 + ) { 110 + fileinto :create "Newsletters"; 111 + stop; 112 + } 113 + 114 + # Everything else -> INBOX 115 + keep; 116 + ''; 117 + }; 118 + "bot@lassul.us" = { 119 + hashedPasswordFile = 120 + config.clan.core.vars.generators.mailserver-bot.files."bot-mail-password-hash".path; 121 + }; 122 + }; 123 + 124 + # TLS via existing ACME cert 125 + x509.useACMEHost = "mail.lassul.us"; 126 + 127 + # DKIM — auto-managed by module 128 + dkimSigning = true; 129 + dkimSelector = "mail"; 130 + 131 + # Full-text search for IMAP clients 132 + fullTextSearch = { 133 + enable = true; 134 + memoryLimit = 500; 135 + }; 136 + 137 + stateVersion = 3; 138 + }; 139 + 140 + # Password generation for mail accounts 141 + clan.core.vars.generators.mailserver-lass = { 142 + files."lass-mail-password" = { }; 143 + files."lass-mail-password-hash" = { }; 144 + runtimeInputs = with pkgs; [ 145 + coreutils 146 + mkpasswd 147 + pwgen 148 + ]; 149 + script = '' 150 + pwgen -s 32 1 > "$out/lass-mail-password" 151 + mkpasswd -sm bcrypt < "$out/lass-mail-password" > "$out/lass-mail-password-hash" 152 + ''; 153 + }; 154 + 155 + clan.core.vars.generators.mailserver-bot = { 156 + files."bot-mail-password" = { }; 157 + files."bot-mail-password-hash" = { }; 158 + runtimeInputs = with pkgs; [ 159 + coreutils 160 + mkpasswd 161 + pwgen 162 + ]; 163 + script = '' 164 + pwgen -s 32 1 > "$out/bot-mail-password" 165 + mkpasswd -sm bcrypt < "$out/bot-mail-password" > "$out/bot-mail-password-hash" 166 + ''; 167 + }; 168 + 169 + # Retiolum relay: allow krebs hosts to relay through postfix 170 + services.postfix.settings.main.mynetworks = lib.mkForce ( 171 + [ 172 + "127.0.0.0/8" 173 + "[::1]/128" 174 + ] 175 + ++ mynetworks 176 + ); 177 + 178 + # ACME cert — reuse existing setup 179 + security.acme.certs."mail.lassul.us" = { 180 + group = "lasscert"; 181 + webroot = "/var/lib/acme/acme-challenge"; 182 + }; 183 + users.groups.lasscert.members = [ 184 + "dovecot2" 185 + "postfix" 186 + "nginx" 187 + ]; 188 + 189 + # Firewall rules (krebs.iptables pattern, INPUT policy is DROP) 190 + krebs.iptables.tables.filter.INPUT.rules = [ 191 + { 192 + predicate = "-p tcp --dport smtp"; 193 + target = "ACCEPT"; 194 + } 195 + { 196 + predicate = "-p tcp --dport submissions"; 197 + target = "ACCEPT"; 198 + } 199 + { 200 + predicate = "-p tcp --dport submission"; 201 + target = "ACCEPT"; 202 + } 203 + { 204 + predicate = "-p tcp --dport imaps"; 205 + target = "ACCEPT"; 206 + } 207 + ]; 208 + 209 + # msmtp for local submission via SSH 210 + environment.systemPackages = [ pkgs.msmtp ]; 211 + }
-8
2configs/riot.nix
··· 97 97 serverAliases = domains; 98 98 }; 99 99 100 - krebs.exim-smarthost.extraRouters = '' 101 - forward_riot: 102 - driver = manualroute 103 - domains = ${lib.concatStringsSep ":" domains} 104 - transport = remote_smtp 105 - route_list = * riot 106 - no_more 107 - ''; 108 100 }
-53
2configs/mail/internet-gateway.nix
··· 1 - { config, pkgs, ... }: 2 - { 3 - networking.firewall.allowedTCPPorts = [ 25 ]; 4 - 5 - security.acme.certs."mail.lassul.us" = { 6 - group = "lasscert"; 7 - webroot = "/var/lib/acme/acme-challenge"; 8 - }; 9 - users.groups.lasscert.members = [ 10 - "exim" 11 - "nginx" 12 - ]; 13 - 14 - clan.core.vars.generators.lassul-us-dkim = { 15 - files."lassul.us.dkim.priv" = { }; 16 - files."lassul.us.dkim.pub" = { }; 17 - migrateFact = "lassul.us-dkim"; 18 - runtimeInputs = with pkgs; [ 19 - coreutils 20 - openssl 21 - ]; 22 - script = '' 23 - openssl genrsa -out "$out"/lassul.us.dkim.priv 2048 24 - openssl rsa -in "$out"/lassul.us.dkim.priv -pubout -outform der 2>/dev/null | openssl base64 -A > "$out"/lassul.us.dkim.pub 25 - ''; 26 - }; 27 - 28 - krebs.exim-smarthost = { 29 - enable = true; 30 - primary_hostname = "lassul.us"; 31 - dkim = [ 32 - { 33 - domain = "lassul.us"; 34 - private_key = config.clan.core.vars.generators.lassul-us-dkim.files."lassul.us.dkim.priv".path; 35 - } 36 - ]; 37 - ssl_cert = "/var/lib/acme/mail.lassul.us/fullchain.pem"; 38 - ssl_key = "/var/lib/acme/mail.lassul.us/key.pem"; 39 - sender_domains = [ "lassul.us" ]; 40 - local_domains = [ 41 - "localhost" 42 - "lassul.us" 43 - ]; 44 - extraRouters = '' 45 - forward_lassul_us: 46 - driver = manualroute 47 - domains = lassul.us 48 - transport = remote_smtp 49 - route_list = * green.r 50 - no_more 51 - ''; 52 - }; 53 - }
+2
machines/neoprism/backup.nix
··· 31 31 "/var/lib/matrix-synapse/media_store/local_content" 32 32 "/var/lib/radicale" 33 33 "/home/bot" 34 + "/var/vmail" 35 + "/var/dkim" 34 36 ]; 35 37 exclude = [ 36 38 "*.pyc"
+1 -1
machines/neoprism/config.nix
··· 5 5 ../../2configs 6 6 ../../2configs/ssh-redirect.nix 7 7 ../../2configs/retiolum.nix 8 - ../../2configs/exim-smarthost.nix 8 + ../../2configs/mailserver.nix 9 9 ../../2configs/gsm-wiki.nix 10 10 ../../2configs/monitoring/telegraf.nix 11 11 ../../2configs/pair-programming.nix