From 4618c3f7fb7400d664b1ef98733607a3ea231933 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 16:20:58 +0100 Subject: [PATCH 01/18] Add mail server to Grafana logs. --- .../modules/scripts/compose_two_nix.zsh | 10 +++++++++- .../modules/system/gramethus.nix | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/nix-system-configs/modules/scripts/compose_two_nix.zsh b/nix-system-configs/modules/scripts/compose_two_nix.zsh index b0e71b0..1e01a26 100755 --- a/nix-system-configs/modules/scripts/compose_two_nix.zsh +++ b/nix-system-configs/modules/scripts/compose_two_nix.zsh @@ -1,3 +1,11 @@ ## Todo, make a proper script for this EDITOR=micro nix-shell -p sops --run "SOPS_AGE_KEY_FILE=$HOME/.config/sops/age/keys.txt sops nix-system-configs/secrets/songsheet/secrets.yaml" -compose2nix --inputs nix-system-configs/modules/songsheet/wavelog/docker-compose.yml --sops_file nix-system-configs/secrets/songsheet/secrets.yaml --project=wavelog --output nix-system-configs/modules/songsheet/wavelog/docker-compose.nix --root_path nix-system-configs/modules/songsheet/wavelog \ No newline at end of file +compose2nix --inputs nix-system-configs/modules/songsheet/wavelog/docker-compose.yml --sops_file nix-system-configs/secrets/songsheet/secrets.yaml --project=wavelog --output nix-system-configs/modules/songsheet/wavelog/docker-compose.nix --root_path nix-system-configs/modules/songsheet/wavelog + + +# Todo make a proper script for this: +NIXOS_CONFIG="/home/nixosbm/the_prg_server_configuration/nix-system-configs/modules/system/mail-server.nix" nixos-rebuild build-image --image-variant proxmox +#Mind the ``` +# - In `/home/nixosbm/the_prg_server_configuration/nix-system-configs/modules/bootloader/seabios-assigned-proxmox-at-birth.nix': "/dev/vda1" +# - In `/nix/var/nix/profiles/per-user/root/channels/nixos/nixos/modules/virtualisation/proxmox-image.nix': "/dev/disk/by-label/nixos" +#``` \ No newline at end of file diff --git a/nix-system-configs/modules/system/gramethus.nix b/nix-system-configs/modules/system/gramethus.nix index d26361f..e6b4e4d 100644 --- a/nix-system-configs/modules/system/gramethus.nix +++ b/nix-system-configs/modules/system/gramethus.nix @@ -130,6 +130,24 @@ in { isDefault = false; editable = true; } + + + { + name = "Prometheus - Mail Server"; + type = "prometheus"; + url = "http://10.1.1.15:9001"; + isDefault = false; + editable = true; + } + + { + name = "Loki - Mail Server"; + type = "loki"; + url = "http://10.1.1.15:3100"; + isDefault = false; + editable = true; + } + ]; }; }; From 1565b21d8bc4236995aed87bf24f78705d02bd31 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 16:34:15 +0100 Subject: [PATCH 02/18] Update keys, add Tailscale to the mailserver --- .sops.yaml | 4 +++- .../modules/system/gramethus.nix | 2 -- .../modules/system/mail-server.nix | 3 +++ nix-system-configs/secrets/mail/secrets.yaml | 19 ++++++++++++++----- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/.sops.yaml b/.sops.yaml index fc66233..a519d2d 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -5,6 +5,7 @@ keys: - &server_database age1k9ddvzypz986a7dt403ja6evql2agz0gehll79mx64zceteya38smxph8m - &server_build_machine age1xtsm7kmql8794756ls53eu8pusyadk4lauadxx867tgsjhd38y5sj7elca - &server_christine age1kzsrlz86y5nqe4vaufv8chupq2hrf3avlmxsp3d5p9t5xj593deszslkmp + - &server_mail age1pkn38zzyckxqgeud7s7y3uuhd7pau3csh56rn3ue4altzkressdsaxs4et creation_rules: - path_regex: nix-system-configs/secrets/songsheet/[^/]+\.(yaml|json|env|ini)$ key_groups: @@ -38,4 +39,5 @@ creation_rules: - path_regex: nix-system-configs/secrets/mail/[^/]+\.(yaml|json|env|ini)$ key_groups: - age: - - *admin_christine \ No newline at end of file + - *admin_christine + - *server_mail \ No newline at end of file diff --git a/nix-system-configs/modules/system/gramethus.nix b/nix-system-configs/modules/system/gramethus.nix index e6b4e4d..0f3a636 100644 --- a/nix-system-configs/modules/system/gramethus.nix +++ b/nix-system-configs/modules/system/gramethus.nix @@ -131,7 +131,6 @@ in { editable = true; } - { name = "Prometheus - Mail Server"; type = "prometheus"; @@ -147,7 +146,6 @@ in { isDefault = false; editable = true; } - ]; }; }; diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index 257f6a7..732c70f 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -41,6 +41,9 @@ in { ]; config = { + # Enable Tailscale for remote access to Traefik dashboard and configuration + services.tailscale.enable = true; + local.hostname = "nixos-mailserver"; local.username = "mailprg"; local.userDescription = "NixOS PRG Mailing Service"; diff --git a/nix-system-configs/secrets/mail/secrets.yaml b/nix-system-configs/secrets/mail/secrets.yaml index a085774..78f108b 100644 --- a/nix-system-configs/secrets/mail/secrets.yaml +++ b/nix-system-configs/secrets/mail/secrets.yaml @@ -7,11 +7,20 @@ sops: - recipient: age1746rvsvsc3snxfl7cndm222wd5kck4aqj3x7nednlegq0gdjhfcqx0qv7m enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBseTM3bTJtamFBVzRkOVpp - bEZNQlJoNUVjTFd0NGl3VktmUUdHWi9wMTM0CnE3bTh5QmM1KzVqTnI3RHdmbXhN - a0NWRkthbG9OZ3pZMEZkU3hjWUNyd1UKLS0tIE5KdXgzQmRRWTVBbDFTSEkzQW9o - ZWE0ci9wSmhpWmc1OHZwb09aTjk1TUUKitmILkhief6sapPh3gZAEDsaHqcv3se0 - +6w+hs05ChkXHQ+JlXOTznd5ZNS4hwOAk5KOconNbauBaKWDplnHhA== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYRFU5S1EvUmFTeFoxQ0dZ + Ymx5Tm92U2NtS2JsaGlzS3Y2Z3dsRGpkOW5BCkxCRXJWMjBkTjdiejg0bGpRcXg0 + UzBzSHUwajRSM2s4bjFWRGNCVDVXclEKLS0tICtxYnZJQm9KcCs1eURCYTUyRHYx + SFQxT0hyZ3A5d1BPbEhWUVJJNFVFM1EKI7Srn4G6r0mKIfPd+VsCCAQGlshirxLS + cvMHhG3WqMV/esuHfi/0xpQuKoCQpBcS2sW/vtJk5Au+uV3dVfv/jg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1pkn38zzyckxqgeud7s7y3uuhd7pau3csh56rn3ue4altzkressdsaxs4et + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvOFYyWGYrUWNDdzBkajlh + RVdENTloUDcvVnhPeHgvcDIzRnNIWUNnS21BCmFhMlVSSk1kNmpUek0yZDh3cGcx + WHltUWVqREhZdlJ2bWJtczJjTXZ3dHcKLS0tIDRweTY1RVdVZVQ1ZlNsc3FwdVdL + OFE3aWxZNThlWUUrUWlwZmtGYjJGT2sKFkoNZt6ThwzwQ2MMFjncrVrLKEhJ1hxh + uJuOfYFlQI80k3etChD64mTRMSK7Cr/BIc2625+jGJK4kOc+JpFDEQ== -----END AGE ENCRYPTED FILE----- lastmodified: "2026-02-15T14:13:19Z" mac: ENC[AES256_GCM,data:7hFjuvictSbcXLqXwG0VgWErKJpFsy1PfDyepQQXpszpMT4Z/BwvXlk4ppKo8C0PaCLv2qi86yBmFm/O6xUBhsMEFWYHQ+mJpYtqLX0GDvj1cn4LwDEnRa+2SiHkkZeHSwrtOHCBw8vE2R2sXBaNMkUoSXkcQ4lPS6YjulpO1vw=,iv:5aZxEnPymcvNpsUyGvvRI3o7hnfExSFWlBrzoIhQkFQ=,tag:6JJGvBL9XeiPw+TdN2qEgA==,type:str] From 70f6cc79302ae748cee4645925364d2ef2c5e871 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 17:24:21 +0100 Subject: [PATCH 03/18] Update mail server secrets references to use direct secret values instead of file paths --- nix-system-configs/modules/system/mail-server.nix | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index 732c70f..7f0a995 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -99,10 +99,10 @@ in { acme."letsencrypt" = { directory = "https://acme-v02.api.letsencrypt.org/directory"; challenge = "dns-01"; - contact = config.sops.secrets."cloudflare-username".path; + contact = config.sops.secrets."cloudflare-username"; domains = ["prg-radio.org" "mail.prg-radio.org"]; provider = "cloudflare"; - secret = config.sops.secrets."cloudflare-dns-token".path; + secret = config.sops.secrets."cloudflare-dns-token"; }; session.auth = { mechanisms = "[plain]"; @@ -117,20 +117,20 @@ in { { class = "individual"; name = "Polyteknisk Radiogruppe Board Member"; - secret = config.sops.secrets."board-member-password".path; + secret = config.sops.secrets."board-member-password"; email = ["board@prg-radio.org"]; } { class = "individual"; name = "postmaster"; - secret = config.sops.secrets."board-member-password".path; + secret = config.sops.secrets."board-member-password"; email = ["postmaster@prg-radio.org"]; } ]; }; authentication.fallback-admin = { user = "admin"; - secret = config.sops.secrets."admin-password".path; + secret = config.sops.secrets."admin-password"; }; }; }; From e7d4f3d4a1c20338cda5ce694e4b29f295c20eb5 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 17:40:37 +0100 Subject: [PATCH 04/18] Update password management. --- .../modules/system/mail-server.nix | 22 ++++++++++++++----- nix-system-configs/secrets/mail/secrets.yaml | 12 +++++----- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index 7f0a995..45b54c1 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -41,6 +41,18 @@ in { ]; config = { + # Pass secrets to Stalwart Mail service via environment variables + systemd.services.stalwart-mail = { + serviceConfig = { + EnvironmentFile = [ + config.sops.secrets."cloudflare-username".path + config.sops.secrets."cloudflare-dns-token".path + config.sops.secrets."admin-password".path + config.sops.secrets."board-member-password".path + ]; + }; + }; + # Enable Tailscale for remote access to Traefik dashboard and configuration services.tailscale.enable = true; @@ -99,10 +111,10 @@ in { acme."letsencrypt" = { directory = "https://acme-v02.api.letsencrypt.org/directory"; challenge = "dns-01"; - contact = config.sops.secrets."cloudflare-username"; + contact = "$CLOUDFLARE_USERNAME"; domains = ["prg-radio.org" "mail.prg-radio.org"]; provider = "cloudflare"; - secret = config.sops.secrets."cloudflare-dns-token"; + secret = "$CLOUDFLARE_API_TOKEN"; }; session.auth = { mechanisms = "[plain]"; @@ -117,20 +129,20 @@ in { { class = "individual"; name = "Polyteknisk Radiogruppe Board Member"; - secret = config.sops.secrets."board-member-password"; + secret = "$BOARD_PASSWORD"; email = ["board@prg-radio.org"]; } { class = "individual"; name = "postmaster"; - secret = config.sops.secrets."board-member-password"; + secret = "$BOARD_PASSWORD"; email = ["postmaster@prg-radio.org"]; } ]; }; authentication.fallback-admin = { user = "admin"; - secret = config.sops.secrets."admin-password"; + secret = "$ADMIN_PASSWORD"; }; }; }; diff --git a/nix-system-configs/secrets/mail/secrets.yaml b/nix-system-configs/secrets/mail/secrets.yaml index 78f108b..653007e 100644 --- a/nix-system-configs/secrets/mail/secrets.yaml +++ b/nix-system-configs/secrets/mail/secrets.yaml @@ -1,7 +1,7 @@ -admin-password: ENC[AES256_GCM,data:o8nD9CDNzufxVjfH7TqUY4QO6Xkz1xbpFu74jMVRR57NDKpKsg3ijRmBvvq1/QuJ2TM=,iv:xVGjzrRFpCyjriW6yB/UjuGiNhK4oeBiDA+Pk/BTOWc=,tag:H/ZuqffTDGsGTWTTKplvvA==,type:str] -board-member-password: ENC[AES256_GCM,data:8KLyqyGFi/ehvbNU6HsWilMO42UnXYL6puc/OOPgMDiU2fuDM2o7TibUCn1BXi9UyiE=,iv:UyLOFSARK/5p/zin7vqQic9C5qlryd/O/mjcw3eZ3ao=,tag:N2RJC6nZC+V3XoAw/eWYfA==,type:str] -cloudflare-dns-token: ENC[AES256_GCM,data:W0S9WWmhQMwjKbKI60vBjYlSb0chZUYcVs3A4DsVRfJwErcIqDWoJg==,iv:nRH8hLvCavydVC16M93N+r/t9WwNY4339CE4zGSINsk=,tag:yIUKs/XB3arhApGeik6p1A==,type:str] -cloudflare-username: ENC[AES256_GCM,data:5QCWOZcv6RKlk1/5LWjjCW0m,iv:9VzhRDlLq36pMfv0tu7POxheLFKdXP8tLLiKlTOr/30=,tag:MiijON1+mKJj6VMdnaJTkA==,type:str] +admin-password: ENC[AES256_GCM,data:1teK0r2L01ZJEdrF343El6GhHnLiqLMItDwy5XAU+uqZyKDb+gvRUaWP2L4BzSSHNqYDGmolyaJnvrMsxW1v3A4=,iv:d7J5vgeX6ZByBcw0im61Uj+hzbSiMdYKEdgqNohPSCA=,tag:gOAVtTGaQJTr4OjWa+7zOA==,type:str] +board-member-password: ENC[AES256_GCM,data:eVQfHApjGtffBJgfAFvThhjMg6IF0zdtATWdYQ3YtKG50hEKrxMW2WoKuadPPlqC3S1D0AId3lg4VxPKY/fN1og=,iv:t92IVJD5ot7gVXkSsWIPJ6LmXVy9Fw6nDSS1ENcOG1w=,tag:lznVB7enNtVYdR+nbGXeZQ==,type:str] +cloudflare-dns-token: ENC[AES256_GCM,data:TT5DaSvU97VPOsgspfbbf4REYByAy37lwRr8CPkGj0sEbYPvzV/Yw/ZMKWVu/SThPloGw/59FSx6o7yW/A==,iv:XfE73U60QguxsQlf5vzsy6dn1CkJLn4OplWAEwOSGe0=,tag:OaUhgMsOJ7npozoLblw/2w==,type:str] +cloudflare-username: ENC[AES256_GCM,data:i7pLjCmZDFZK/LcjO4vGrvhLtZqexF8X0ARmg0i/LsdP357OaPo=,iv:+841JT7nsdhqTWEMdEfJTYqqOoM2g9hoSz24q6aL4pw=,tag:Uqds4MZ179VcsicfifbHXQ==,type:str] sops: age: - recipient: age1746rvsvsc3snxfl7cndm222wd5kck4aqj3x7nednlegq0gdjhfcqx0qv7m @@ -22,7 +22,7 @@ sops: OFE3aWxZNThlWUUrUWlwZmtGYjJGT2sKFkoNZt6ThwzwQ2MMFjncrVrLKEhJ1hxh uJuOfYFlQI80k3etChD64mTRMSK7Cr/BIc2625+jGJK4kOc+JpFDEQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-02-15T14:13:19Z" - mac: ENC[AES256_GCM,data:7hFjuvictSbcXLqXwG0VgWErKJpFsy1PfDyepQQXpszpMT4Z/BwvXlk4ppKo8C0PaCLv2qi86yBmFm/O6xUBhsMEFWYHQ+mJpYtqLX0GDvj1cn4LwDEnRa+2SiHkkZeHSwrtOHCBw8vE2R2sXBaNMkUoSXkcQ4lPS6YjulpO1vw=,iv:5aZxEnPymcvNpsUyGvvRI3o7hnfExSFWlBrzoIhQkFQ=,tag:6JJGvBL9XeiPw+TdN2qEgA==,type:str] + lastmodified: "2026-02-15T16:35:00Z" + mac: ENC[AES256_GCM,data:LShVAjb1lCGq91O2mAwa7OzzOC01NrrSxnhLFPdbf8M93xXJSpz7U2GDQwfQ/3BsnIJiSgSLhrMYkNhDITaDWY90SrnL+tm0MhozQeiuKyfVal2Dr8P0VvxTxSaqemoFeyUvmJwe7rSjoEQnJYduilMqzhOcB/MkAivNeHnhQMQ=,iv:7zeV6HANpV0zGAg7UnM9l45FhO3jsOkzxMbJ1pTIIxU=,tag:3078xKYVrObEYSr8LAh9eg==,type:str] unencrypted_suffix: _unencrypted version: 3.11.0 From 5289fc4a200a54ab338b8f4c20db08a4b189aaa0 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 18:17:03 +0100 Subject: [PATCH 05/18] Update password management... again. --- nix-system-configs/modules/system/mail-server.nix | 11 +++++------ nix-system-configs/secrets/mail/secrets.yaml | 12 ++++++------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index 45b54c1..fb8bcf1 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -44,15 +44,14 @@ in { # Pass secrets to Stalwart Mail service via environment variables systemd.services.stalwart-mail = { serviceConfig = { - EnvironmentFile = [ - config.sops.secrets."cloudflare-username".path - config.sops.secrets."cloudflare-dns-token".path - config.sops.secrets."admin-password".path - config.sops.secrets."board-member-password".path + Environment = [ + (let v = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."cloudflare-username".path); in "CLOUDFLARE_USERNAME=${v}") + (let v = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."cloudflare-dns-token".path); in "CLOUDFLARE_API_TOKEN=${v}") + (let v = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."admin-password".path); in "ADMIN_PASSWORD=${v}") + (let v = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."board-member-password".path); in "BOARD_PASSWORD=${v}") ]; }; }; - # Enable Tailscale for remote access to Traefik dashboard and configuration services.tailscale.enable = true; diff --git a/nix-system-configs/secrets/mail/secrets.yaml b/nix-system-configs/secrets/mail/secrets.yaml index 653007e..3cd54e0 100644 --- a/nix-system-configs/secrets/mail/secrets.yaml +++ b/nix-system-configs/secrets/mail/secrets.yaml @@ -1,7 +1,7 @@ -admin-password: ENC[AES256_GCM,data:1teK0r2L01ZJEdrF343El6GhHnLiqLMItDwy5XAU+uqZyKDb+gvRUaWP2L4BzSSHNqYDGmolyaJnvrMsxW1v3A4=,iv:d7J5vgeX6ZByBcw0im61Uj+hzbSiMdYKEdgqNohPSCA=,tag:gOAVtTGaQJTr4OjWa+7zOA==,type:str] -board-member-password: ENC[AES256_GCM,data:eVQfHApjGtffBJgfAFvThhjMg6IF0zdtATWdYQ3YtKG50hEKrxMW2WoKuadPPlqC3S1D0AId3lg4VxPKY/fN1og=,iv:t92IVJD5ot7gVXkSsWIPJ6LmXVy9Fw6nDSS1ENcOG1w=,tag:lznVB7enNtVYdR+nbGXeZQ==,type:str] -cloudflare-dns-token: ENC[AES256_GCM,data:TT5DaSvU97VPOsgspfbbf4REYByAy37lwRr8CPkGj0sEbYPvzV/Yw/ZMKWVu/SThPloGw/59FSx6o7yW/A==,iv:XfE73U60QguxsQlf5vzsy6dn1CkJLn4OplWAEwOSGe0=,tag:OaUhgMsOJ7npozoLblw/2w==,type:str] -cloudflare-username: ENC[AES256_GCM,data:i7pLjCmZDFZK/LcjO4vGrvhLtZqexF8X0ARmg0i/LsdP357OaPo=,iv:+841JT7nsdhqTWEMdEfJTYqqOoM2g9hoSz24q6aL4pw=,tag:Uqds4MZ179VcsicfifbHXQ==,type:str] +admin-password: ENC[AES256_GCM,data:GxV2THg8b6sa1B9kjoBpN5nPgIUIzGdCE3kUJx+Ik8mO9VGwLU//giTXrd983QDqNVc=,iv:0qbCOVT5z53gqEjFHAXLsyD+nCHGk+3Rn2Qt+ifgRJw=,tag:HDEir7oY5mpfpeyaVOUMJw==,type:str] +board-member-password: ENC[AES256_GCM,data:IHpjcweY0hQZObrrfbq67cQYJuYBS4zgcGoWcY487wqk2pPbNUOMAun9RzWXAk4X6N0=,iv:aVZArmVCSADLozsnDDhxKUizJ5CVmymKfaANcrniFvY=,tag:TGrpwrEUd5fdLyvYx8olZw==,type:str] +cloudflare-dns-token: ENC[AES256_GCM,data:IpgU7An3IW/LFL+5OJ3oYH4c3eZjZFP+qK8/oFsNCorYKVaWPVOIVA==,iv:49UwRT8DfbC9ZIXgx7nCSxjHeIIAkiHD70ti3rWUexA=,tag:Vn9wVUhTgRlGG9E+i9NzGw==,type:str] +cloudflare-username: ENC[AES256_GCM,data:AMgWBFP90f1ML/I6es0HIUoW,iv:64GGNMSdTrmurEsgdI82iTqD9FUW8leKu/JvT7Ls6Og=,tag:3rTWNF3NfTExCnV+RRwyVA==,type:str] sops: age: - recipient: age1746rvsvsc3snxfl7cndm222wd5kck4aqj3x7nednlegq0gdjhfcqx0qv7m @@ -22,7 +22,7 @@ sops: OFE3aWxZNThlWUUrUWlwZmtGYjJGT2sKFkoNZt6ThwzwQ2MMFjncrVrLKEhJ1hxh uJuOfYFlQI80k3etChD64mTRMSK7Cr/BIc2625+jGJK4kOc+JpFDEQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-02-15T16:35:00Z" - mac: ENC[AES256_GCM,data:LShVAjb1lCGq91O2mAwa7OzzOC01NrrSxnhLFPdbf8M93xXJSpz7U2GDQwfQ/3BsnIJiSgSLhrMYkNhDITaDWY90SrnL+tm0MhozQeiuKyfVal2Dr8P0VvxTxSaqemoFeyUvmJwe7rSjoEQnJYduilMqzhOcB/MkAivNeHnhQMQ=,iv:7zeV6HANpV0zGAg7UnM9l45FhO3jsOkzxMbJ1pTIIxU=,tag:3078xKYVrObEYSr8LAh9eg==,type:str] + lastmodified: "2026-02-15T17:16:50Z" + mac: ENC[AES256_GCM,data:4FZe4zCBQY01TcsX8yU5cMz8C1C64L80QJFhhdC+3xxS0URw/QkpyevUnkT7gzmuHjwBbrdY/NpNTyNfzacxpw2dVt4MhvdDcKWqXV802DmBpaZcvfFlsjpSBIhXiudu428tQOwWgY3WmQfmg2wh46fRM8+QoZyaxOaX188Pu9U=,iv:EUuzxfz3cGK2yf555PQNpRCzOvlSVKLihBkUxNp8JjQ=,tag:L92aHzdQAY5K0QxkFpFvOQ==,type:str] unencrypted_suffix: _unencrypted version: 3.11.0 From 8963c8d048e12488b50a7a706128116d3fa9dc50 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 18:54:16 +0100 Subject: [PATCH 06/18] Revamp password, change password... --- .../modules/system/mail-server.nix | 46 +++++++++++-------- nix-system-configs/secrets/mail/secrets.yaml | 8 ++-- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index fb8bcf1..58a81c3 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -5,6 +5,14 @@ ... }: let choose = paths: lib.findFirst builtins.pathExists null paths; + # Read secrets from sops-managed files and trim trailing newlines so the + # generated stalwart config contains the actual secret values (not the + # literal "$FOO" placeholders). Using builtins.readFile here ensures the + # values are placed into the TOML at build time. + adminPassword = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."admin-password".path); + boardPassword = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."board-member-password".path); + cloudflareUsername = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."cloudflare-username".path); + cloudflareToken = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."cloudflare-dns-token".path); in { options.local = { hostname = lib.mkOption { @@ -41,17 +49,18 @@ in { ]; config = { - # Pass secrets to Stalwart Mail service via environment variables - systemd.services.stalwart-mail = { - serviceConfig = { - Environment = [ - (let v = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."cloudflare-username".path); in "CLOUDFLARE_USERNAME=${v}") - (let v = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."cloudflare-dns-token".path); in "CLOUDFLARE_API_TOKEN=${v}") - (let v = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."admin-password".path); in "ADMIN_PASSWORD=${v}") - (let v = builtins.replaceStrings ["\n"] [""] (builtins.readFile config.sops.secrets."board-member-password".path); in "BOARD_PASSWORD=${v}") - ]; - }; + # Create /etc/stalwart secret files so the generated TOML can reference them + environment.etc = { + "stalwart/mail-pw1".text = boardPassword; # principal password (board) + "stalwart/mail-pw1".mode = "0400"; + "stalwart/admin-pw".text = adminPassword; # admin fallback password + "stalwart/admin-pw".mode = "0400"; + "stalwart/acme-secret".text = cloudflareToken; # API token for ACME (Cloudflare) + "stalwart/acme-secret".mode = "0400"; + "stalwart/cloudflare-username".text = cloudflareUsername; # contact email for ACME + "stalwart/cloudflare-username".mode = "0400"; }; + # Enable Tailscale for remote access to Traefik dashboard and configuration services.tailscale.enable = true; @@ -110,17 +119,18 @@ in { acme."letsencrypt" = { directory = "https://acme-v02.api.letsencrypt.org/directory"; challenge = "dns-01"; - contact = "$CLOUDFLARE_USERNAME"; + # reference the contact and secret via files under /etc/stalwart + contact = "%{file:/etc/stalwart/cloudflare-username}%"; domains = ["prg-radio.org" "mail.prg-radio.org"]; provider = "cloudflare"; - secret = "$CLOUDFLARE_API_TOKEN"; + secret = "%{file:/etc/stalwart/acme-secret}%"; }; session.auth = { - mechanisms = "[plain]"; - directory = "'in-memory'"; + mechanisms = ["plain"]; + directory = "in-memory"; }; storage.directory = "in-memory"; - session.rcpt.directory = "'in-memory'"; + session.rcpt.directory = "in-memory"; directory."imap".lookup.domains = ["prg-radio.org"]; directory."in-memory" = { type = "memory"; @@ -128,20 +138,20 @@ in { { class = "individual"; name = "Polyteknisk Radiogruppe Board Member"; - secret = "$BOARD_PASSWORD"; + secret = "%{file:/etc/stalwart/mail-pw1}%"; email = ["board@prg-radio.org"]; } { class = "individual"; name = "postmaster"; - secret = "$BOARD_PASSWORD"; + secret = "%{file:/etc/stalwart/mail-pw1}%"; email = ["postmaster@prg-radio.org"]; } ]; }; authentication.fallback-admin = { user = "admin"; - secret = "$ADMIN_PASSWORD"; + secret = "%{file:/etc/stalwart/admin-pw}%"; }; }; }; diff --git a/nix-system-configs/secrets/mail/secrets.yaml b/nix-system-configs/secrets/mail/secrets.yaml index 3cd54e0..fc3b5c2 100644 --- a/nix-system-configs/secrets/mail/secrets.yaml +++ b/nix-system-configs/secrets/mail/secrets.yaml @@ -1,5 +1,5 @@ -admin-password: ENC[AES256_GCM,data:GxV2THg8b6sa1B9kjoBpN5nPgIUIzGdCE3kUJx+Ik8mO9VGwLU//giTXrd983QDqNVc=,iv:0qbCOVT5z53gqEjFHAXLsyD+nCHGk+3Rn2Qt+ifgRJw=,tag:HDEir7oY5mpfpeyaVOUMJw==,type:str] -board-member-password: ENC[AES256_GCM,data:IHpjcweY0hQZObrrfbq67cQYJuYBS4zgcGoWcY487wqk2pPbNUOMAun9RzWXAk4X6N0=,iv:aVZArmVCSADLozsnDDhxKUizJ5CVmymKfaANcrniFvY=,tag:TGrpwrEUd5fdLyvYx8olZw==,type:str] +admin-password: ENC[AES256_GCM,data:036xX0rMzmQn0iFBYEU2u6Xa,iv:fsWHfakdNdNf8r0PrazuTbBeHmaeVqP+9l4Ip6Yx3nM=,tag:sbYB+wMOckVtBaac84zEow==,type:str] +board-member-password: ENC[AES256_GCM,data:e8jdc6FVBwB2Ieqty9s4d/aASdY=,iv:E09RhJOB84ad+L7zRXROLGD1RgDUYe/DOJCbz/zFN08=,tag:fboTZGEnrBz5pMGqwIXSTA==,type:str] cloudflare-dns-token: ENC[AES256_GCM,data:IpgU7An3IW/LFL+5OJ3oYH4c3eZjZFP+qK8/oFsNCorYKVaWPVOIVA==,iv:49UwRT8DfbC9ZIXgx7nCSxjHeIIAkiHD70ti3rWUexA=,tag:Vn9wVUhTgRlGG9E+i9NzGw==,type:str] cloudflare-username: ENC[AES256_GCM,data:AMgWBFP90f1ML/I6es0HIUoW,iv:64GGNMSdTrmurEsgdI82iTqD9FUW8leKu/JvT7Ls6Og=,tag:3rTWNF3NfTExCnV+RRwyVA==,type:str] sops: @@ -22,7 +22,7 @@ sops: OFE3aWxZNThlWUUrUWlwZmtGYjJGT2sKFkoNZt6ThwzwQ2MMFjncrVrLKEhJ1hxh uJuOfYFlQI80k3etChD64mTRMSK7Cr/BIc2625+jGJK4kOc+JpFDEQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-02-15T17:16:50Z" - mac: ENC[AES256_GCM,data:4FZe4zCBQY01TcsX8yU5cMz8C1C64L80QJFhhdC+3xxS0URw/QkpyevUnkT7gzmuHjwBbrdY/NpNTyNfzacxpw2dVt4MhvdDcKWqXV802DmBpaZcvfFlsjpSBIhXiudu428tQOwWgY3WmQfmg2wh46fRM8+QoZyaxOaX188Pu9U=,iv:EUuzxfz3cGK2yf555PQNpRCzOvlSVKLihBkUxNp8JjQ=,tag:L92aHzdQAY5K0QxkFpFvOQ==,type:str] + lastmodified: "2026-02-15T17:53:57Z" + mac: ENC[AES256_GCM,data:ZdDyFxbaUq/FPSe6z3+FhRJ6GeG4YjGc0fIVof/Sf/gsfKwZAStZs3CKxZtJXxUGBtkw93aguYjnNfxjUH+YxTemZPhWfJZo0pcR9YwWzXvB9fRLM95v/TzWY9qzqqbqVUSz+2SSfUJJG2+dKuzEzA3c1lE1pwOFXdfWOm0+uCE=,iv:mQp+yIVMDBY3tAPlDShk3IlIJ3cb4zrTn18x4HY+YsI=,tag:QLq34VwtxN5t66aE31LcYA==,type:str] unencrypted_suffix: _unencrypted version: 3.11.0 From 64d59dd6366d12bb78ced17a9abce3cec86856f3 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 19:03:14 +0100 Subject: [PATCH 07/18] Fix the file permissions. --- nix-system-configs/modules/system/mail-server.nix | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index 58a81c3..60820e3 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -52,13 +52,17 @@ in { # Create /etc/stalwart secret files so the generated TOML can reference them environment.etc = { "stalwart/mail-pw1".text = boardPassword; # principal password (board) - "stalwart/mail-pw1".mode = "0400"; + "stalwart/mail-pw1".mode = "0440"; + "stalwart/mail-pw1".owner = "stalwart"; "stalwart/admin-pw".text = adminPassword; # admin fallback password - "stalwart/admin-pw".mode = "0400"; + "stalwart/admin-pw".mode = "0440"; + "stalwart/admin-pw".owner = "root"; "stalwart/acme-secret".text = cloudflareToken; # API token for ACME (Cloudflare) - "stalwart/acme-secret".mode = "0400"; + "stalwart/acme-secret".mode = "0440"; + "stalwart/acme-secret".owner = "stalwart"; "stalwart/cloudflare-username".text = cloudflareUsername; # contact email for ACME - "stalwart/cloudflare-username".mode = "0400"; + "stalwart/cloudflare-username".mode = "0440"; + "stalwart/cloudflare-username".owner = "stalwart"; }; # Enable Tailscale for remote access to Traefik dashboard and configuration @@ -93,7 +97,7 @@ in { protocol = "smtp"; tls.implicit = true; # Also trust proxy for SMTPS - proxy.trusted-networks = ["10.1.1.250/32"]; + proxy.trusted-networks = ["10.1.1.250/31"]; }; imaps = { bind = "[::]:993"; From a8c4486c20b157d8514b8eab85fbe0c64f9d4ed7 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 19:05:05 +0100 Subject: [PATCH 08/18] Typo... --- nix-system-configs/modules/system/mail-server.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index 60820e3..ab584d2 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -53,16 +53,16 @@ in { environment.etc = { "stalwart/mail-pw1".text = boardPassword; # principal password (board) "stalwart/mail-pw1".mode = "0440"; - "stalwart/mail-pw1".owner = "stalwart"; + "stalwart/mail-pw1".user = "stalwart"; "stalwart/admin-pw".text = adminPassword; # admin fallback password "stalwart/admin-pw".mode = "0440"; - "stalwart/admin-pw".owner = "root"; + "stalwart/admin-pw".user = "stalwart"; "stalwart/acme-secret".text = cloudflareToken; # API token for ACME (Cloudflare) "stalwart/acme-secret".mode = "0440"; - "stalwart/acme-secret".owner = "stalwart"; + "stalwart/acme-secret".user = "stalwart"; "stalwart/cloudflare-username".text = cloudflareUsername; # contact email for ACME "stalwart/cloudflare-username".mode = "0440"; - "stalwart/cloudflare-username".owner = "stalwart"; + "stalwart/cloudflare-username".user = "stalwart"; }; # Enable Tailscale for remote access to Traefik dashboard and configuration From a3249aa479a608e467528663404ea1657ad209b0 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 20:06:23 +0100 Subject: [PATCH 09/18] Expose mail web admin UI via Traefik under /management and update file permissions --- .../modules/system/mail-server.nix | 20 ++++++++++-------- nix-system-configs/modules/system/traefik.nix | 21 +++++++++++++++++++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index ab584d2..d48f4da 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -52,19 +52,21 @@ in { # Create /etc/stalwart secret files so the generated TOML can reference them environment.etc = { "stalwart/mail-pw1".text = boardPassword; # principal password (board) - "stalwart/mail-pw1".mode = "0440"; - "stalwart/mail-pw1".user = "stalwart"; + "stalwart/mail-pw1".mode = "0777"; "stalwart/admin-pw".text = adminPassword; # admin fallback password - "stalwart/admin-pw".mode = "0440"; - "stalwart/admin-pw".user = "stalwart"; + "stalwart/admin-pw".mode = "0777"; "stalwart/acme-secret".text = cloudflareToken; # API token for ACME (Cloudflare) - "stalwart/acme-secret".mode = "0440"; - "stalwart/acme-secret".user = "stalwart"; + "stalwart/acme-secret".mode = "0777"; "stalwart/cloudflare-username".text = cloudflareUsername; # contact email for ACME - "stalwart/cloudflare-username".mode = "0440"; - "stalwart/cloudflare-username".user = "stalwart"; + "stalwart/cloudflare-username".mode = "0777"; }; + + systemd.tmpfiles.rules = [ + # z = create/modify file or directory, set mode and owner + "z /etc/stalwart 0555 root root - -" + ]; + # Enable Tailscale for remote access to Traefik dashboard and configuration services.tailscale.enable = true; @@ -111,7 +113,7 @@ in { protocol = "http"; }; management = { - bind = ["127.0.0.1:8080"]; + bind = ["127.0.0.1:8080" "[::]:8081"]; protocol = "http"; }; }; diff --git a/nix-system-configs/modules/system/traefik.nix b/nix-system-configs/modules/system/traefik.nix index 7275a45..dc27bbc 100644 --- a/nix-system-configs/modules/system/traefik.nix +++ b/nix-system-configs/modules/system/traefik.nix @@ -309,6 +309,10 @@ in { scheme = "https"; }; }; + # Middleware to strip the /management prefix when proxying to the mail admin + mail-strip-management = { + stripPrefix = { prefixes = ["/management"]; }; + }; }; http.routers = { @@ -372,6 +376,16 @@ in { entryPoints = ["websecure"]; tls = {certresolver = "acme";}; }; + + # Mail web administration UI (Stalwart management) - exposed under /management + mail-webadmin = { + rule = "Host(`mail.prg-radio.org`) && PathPrefix(`/management`)"; + service = "mail-webadmin"; + entryPoints = ["websecure"]; + tls = { certresolver = "acme"; }; + # strip the /management prefix before proxying to the backend + middlewares = ["mail-strip-management"]; + }; }; http.services = { @@ -414,6 +428,13 @@ in { mail-jmap.loadBalancer = { servers = [{url = "http://10.1.1.15:8080";}]; }; + + # Mail webadmin backend (management). Traefik will strip the /management + # prefix and forward the remainder to the management listener on the mail + # server which is bound to port 8081. + mail-webadmin.loadBalancer = { + servers = [{url = "http://10.1.1.15:8081";}]; + }; }; # TCP routing for TeamSpeak From 8c6571727b51a7745b468e8001db84dac087644c Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 20:17:02 +0100 Subject: [PATCH 10/18] I forgot the bloody ports! --- nix-system-configs/modules/system/traefik.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix-system-configs/modules/system/traefik.nix b/nix-system-configs/modules/system/traefik.nix index dc27bbc..6a987d3 100644 --- a/nix-system-configs/modules/system/traefik.nix +++ b/nix-system-configs/modules/system/traefik.nix @@ -567,8 +567,8 @@ in { wants = ["acme-finished-prg-radio.org.target"]; }; - networking.firewall.allowedTCPPorts = [80 443 10022 30033 8448 9001 3001]; - networking.firewall.allowedUDPPorts = [80 443 9987 9001 3001]; + networking.firewall.allowedTCPPorts = [80 443 10022 30033 8448 9001 3001 993 465]; + networking.firewall.allowedUDPPorts = [80 443 9987 9001 3001 993 465]; system.stateVersion = "25.11"; }; From 6f536f306f0f326342b7a87feeb5ae9383ca2342 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 20:57:51 +0100 Subject: [PATCH 11/18] Enable SMTP entrypoint... spooky. --- .../modules/system/mail-server.nix | 1 - nix-system-configs/modules/system/traefik.nix | 18 +++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index d48f4da..5f23077 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -61,7 +61,6 @@ in { "stalwart/cloudflare-username".mode = "0777"; }; - systemd.tmpfiles.rules = [ # z = create/modify file or directory, set mode and owner "z /etc/stalwart 0555 root root - -" diff --git a/nix-system-configs/modules/system/traefik.nix b/nix-system-configs/modules/system/traefik.nix index 6a987d3..13a80fb 100644 --- a/nix-system-configs/modules/system/traefik.nix +++ b/nix-system-configs/modules/system/traefik.nix @@ -267,10 +267,10 @@ in { }; # Mail entrypoints: plain SMTP, implicit SMTPS (465) and IMAPS (993) - #smtp = { - # # plain SMTP (port 25) - TCP passthrough to backend - # address = "[::]:25"; - # }; + smtp = { + # plain SMTP (port 25) - TCP passthrough to backend + address = "[::]:25"; + }; smtps = { # implicit TLS SMTP (port 465) - passthrough to backend address = "[::]:465"; @@ -311,7 +311,7 @@ in { }; # Middleware to strip the /management prefix when proxying to the mail admin mail-strip-management = { - stripPrefix = { prefixes = ["/management"]; }; + stripPrefix = {prefixes = ["/management"];}; }; }; @@ -382,7 +382,7 @@ in { rule = "Host(`mail.prg-radio.org`) && PathPrefix(`/management`)"; service = "mail-webadmin"; entryPoints = ["websecure"]; - tls = { certresolver = "acme"; }; + tls = {certresolver = "acme";}; # strip the /management prefix before proxying to the backend middlewares = ["mail-strip-management"]; }; @@ -516,9 +516,9 @@ in { }; # Mail TCP services - # mail-smtp.loadBalancer = { - # servers = [ { address = "10.1.1.15:25"; } ]; - # }; + mail-smtp.loadBalancer = { + servers = [{address = "10.1.1.15:25";}]; + }; mail-smtps.loadBalancer = { servers = [{address = "10.1.1.15:465";}]; From e389ebb672bacd4abae693154ec6f0ff715e517d Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 21:04:33 +0100 Subject: [PATCH 12/18] Forgor... again. --- nix-system-configs/modules/system/traefik.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix-system-configs/modules/system/traefik.nix b/nix-system-configs/modules/system/traefik.nix index 13a80fb..ac89e9b 100644 --- a/nix-system-configs/modules/system/traefik.nix +++ b/nix-system-configs/modules/system/traefik.nix @@ -567,8 +567,8 @@ in { wants = ["acme-finished-prg-radio.org.target"]; }; - networking.firewall.allowedTCPPorts = [80 443 10022 30033 8448 9001 3001 993 465]; - networking.firewall.allowedUDPPorts = [80 443 9987 9001 3001 993 465]; + networking.firewall.allowedTCPPorts = [80 443 10022 30033 8448 9001 3001 993 465 25]; + networking.firewall.allowedUDPPorts = [80 443 9987 9001 3001 993 465 25]; system.stateVersion = "25.11"; }; From c884036b7a6669fa2ba44055d347effa54f18a2f Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 21:08:27 +0100 Subject: [PATCH 13/18] Forgor... again... added SMTP properly. --- nix-system-configs/modules/system/traefik.nix | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nix-system-configs/modules/system/traefik.nix b/nix-system-configs/modules/system/traefik.nix index ac89e9b..76bf4ed 100644 --- a/nix-system-configs/modules/system/traefik.nix +++ b/nix-system-configs/modules/system/traefik.nix @@ -474,12 +474,12 @@ in { }; # Mail TCP routers: SMTP (25), SMTPS (465 implicit TLS), IMAPS (993 implicit TLS) - #mail-smtp = { - # # catch-all TCP router for port 25 - # rule = "HostSNI(`*`)"; - # service = "mail-smtp"; - # entryPoints = ["smtp"]; - # }; + mail-smtp = { + # catch-all TCP router for port 25 + rule = "HostSNI(`*`)"; + service = "mail-smtp"; + entryPoints = ["smtp"]; + }; mail-smtps = { # SMTPS implicit TLS - passthrough to backend From ba7e32a2a7b2a3d2c4d16af57d852f9e54107488 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 22:18:51 +0100 Subject: [PATCH 14/18] Try to investiagte the header issue. --- nix-system-configs/modules/system/mail-server.nix | 2 +- nix-system-configs/modules/system/traefik.nix | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index 5f23077..4419ab6 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -98,7 +98,7 @@ in { protocol = "smtp"; tls.implicit = true; # Also trust proxy for SMTPS - proxy.trusted-networks = ["10.1.1.250/31"]; + proxy.trusted-networks = ["10.1.1.250/32"]; }; imaps = { bind = "[::]:993"; diff --git a/nix-system-configs/modules/system/traefik.nix b/nix-system-configs/modules/system/traefik.nix index 76bf4ed..4bf7731 100644 --- a/nix-system-configs/modules/system/traefik.nix +++ b/nix-system-configs/modules/system/traefik.nix @@ -517,14 +517,17 @@ in { # Mail TCP services mail-smtp.loadBalancer = { + proxyProtocol = { version = 2; }; # Add this line servers = [{address = "10.1.1.15:25";}]; }; mail-smtps.loadBalancer = { + proxyProtocol = { version = 2; }; # Add this line servers = [{address = "10.1.1.15:465";}]; }; mail-imaps.loadBalancer = { + proxyProtocol = { version = 2; }; # Add this line servers = [{address = "10.1.1.15:993";}]; }; }; From 1bc85803a9907c668f38093fb7709fb104d84d50 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 23:16:59 +0100 Subject: [PATCH 15/18] Diagnose certificate issues, add missing ServerAliases --- .../modules/system/mail-server.nix | 18 +++++++++--------- nix-system-configs/modules/system/traefik.nix | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index 4419ab6..3c12a76 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -121,15 +121,15 @@ in { hostname = "mail.prg-radio.org"; domain = "prg-radio.org"; }; - acme."letsencrypt" = { - directory = "https://acme-v02.api.letsencrypt.org/directory"; - challenge = "dns-01"; - # reference the contact and secret via files under /etc/stalwart - contact = "%{file:/etc/stalwart/cloudflare-username}%"; - domains = ["prg-radio.org" "mail.prg-radio.org"]; - provider = "cloudflare"; - secret = "%{file:/etc/stalwart/acme-secret}%"; - }; + # acme."letsencrypt" = { + # directory = "https://acme-v02.api.letsencrypt.org/directory"; + # challenge = "dns-01"; + # # reference the contact and secret via files under /etc/stalwart + # contact = "%{file:/etc/stalwart/cloudflare-username}%"; + # domains = ["prg-radio.org" "mail.prg-radio.org"]; + # provider = "cloudflare"; + # secret = "%{file:/etc/stalwart/acme-secret}%"; + #}; session.auth = { mechanisms = ["plain"]; directory = "in-memory"; diff --git a/nix-system-configs/modules/system/traefik.nix b/nix-system-configs/modules/system/traefik.nix index 4bf7731..349b15e 100644 --- a/nix-system-configs/modules/system/traefik.nix +++ b/nix-system-configs/modules/system/traefik.nix @@ -371,7 +371,7 @@ in { # Mail HTTP (JMAP / web) - terminate TLS at Traefik and forward to Stalwart JMAP HTTP listener mail = { - rule = "Host(`mail.prg-radio.org`)"; + rule = "Host(`mail.prg-radio.org`,`mta-sts.prg-radio.org`,`autoconfig.prg-radio.org`,`autodiscover.prg-radio.org`)"; service = "mail-jmap"; entryPoints = ["websecure"]; tls = {certresolver = "acme";}; @@ -379,7 +379,7 @@ in { # Mail web administration UI (Stalwart management) - exposed under /management mail-webadmin = { - rule = "Host(`mail.prg-radio.org`) && PathPrefix(`/management`)"; + rule = "Host(`mail.prg-radio.org`,`mta-sts.prg-radio.org`,`autoconfig.prg-radio.org`,`autodiscover.prg-radio.org`) && PathPrefix(`/management`)"; service = "mail-webadmin"; entryPoints = ["websecure"]; tls = {certresolver = "acme";}; @@ -517,17 +517,17 @@ in { # Mail TCP services mail-smtp.loadBalancer = { - proxyProtocol = { version = 2; }; # Add this line + proxyProtocol = {version = 2;}; # Add this line servers = [{address = "10.1.1.15:25";}]; }; mail-smtps.loadBalancer = { - proxyProtocol = { version = 2; }; # Add this line + proxyProtocol = {version = 2;}; # Add this line servers = [{address = "10.1.1.15:465";}]; }; mail-imaps.loadBalancer = { - proxyProtocol = { version = 2; }; # Add this line + proxyProtocol = {version = 2;}; # Add this line servers = [{address = "10.1.1.15:993";}]; }; }; From acdd65a5fb58d8410e93fc00e9583b27da0aa309 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 23:32:23 +0100 Subject: [PATCH 16/18] Renable certificates. --- .../modules/system/mail-server.nix | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index 3c12a76..b3008e7 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -121,15 +121,15 @@ in { hostname = "mail.prg-radio.org"; domain = "prg-radio.org"; }; - # acme."letsencrypt" = { - # directory = "https://acme-v02.api.letsencrypt.org/directory"; - # challenge = "dns-01"; - # # reference the contact and secret via files under /etc/stalwart - # contact = "%{file:/etc/stalwart/cloudflare-username}%"; - # domains = ["prg-radio.org" "mail.prg-radio.org"]; - # provider = "cloudflare"; - # secret = "%{file:/etc/stalwart/acme-secret}%"; - #}; + acme."letsencrypt" = { + directory = "https://acme-v02.api.letsencrypt.org/directory"; + challenge = "dns-01"; + # reference the contact and secret via files under /etc/stalwart + contact = "%{file:/etc/stalwart/cloudflare-username}%"; + domains = ["prg-radio.org" "mail.prg-radio.org"]; + provider = "cloudflare"; + secret = "%{file:/etc/stalwart/acme-secret}%"; + }; session.auth = { mechanisms = ["plain"]; directory = "in-memory"; From 84d2ce3d2f33ff52cd5b01c76986f3b36fa94d9a Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 23:41:41 +0100 Subject: [PATCH 17/18] Remove proxy.trusted-networks configuration from SMTP, SMTPS, and IMAPS services --- nix-system-configs/modules/system/mail-server.nix | 6 ------ 1 file changed, 6 deletions(-) diff --git a/nix-system-configs/modules/system/mail-server.nix b/nix-system-configs/modules/system/mail-server.nix index b3008e7..0b18ed0 100644 --- a/nix-system-configs/modules/system/mail-server.nix +++ b/nix-system-configs/modules/system/mail-server.nix @@ -89,22 +89,16 @@ in { smtp = { protocol = "smtp"; bind = "[::]:25"; - proxy.trusted-networks = [ - "10.1.1.250/32" - ]; }; submissions = { bind = "[::]:465"; protocol = "smtp"; tls.implicit = true; - # Also trust proxy for SMTPS - proxy.trusted-networks = ["10.1.1.250/32"]; }; imaps = { bind = "[::]:993"; protocol = "imap"; tls.implicit = true; - proxy.trusted-networks = ["10.1.1.250/32"]; }; jmap = { bind = "[::]:8080"; From cab31335ff47090ad0703a6b2a671c05917b9e9d Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Sun, 15 Feb 2026 23:47:58 +0100 Subject: [PATCH 18/18] Remove dangling aliases. --- nix-system-configs/modules/system/traefik.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix-system-configs/modules/system/traefik.nix b/nix-system-configs/modules/system/traefik.nix index 349b15e..5c20f91 100644 --- a/nix-system-configs/modules/system/traefik.nix +++ b/nix-system-configs/modules/system/traefik.nix @@ -371,7 +371,7 @@ in { # Mail HTTP (JMAP / web) - terminate TLS at Traefik and forward to Stalwart JMAP HTTP listener mail = { - rule = "Host(`mail.prg-radio.org`,`mta-sts.prg-radio.org`,`autoconfig.prg-radio.org`,`autodiscover.prg-radio.org`)"; + rule = "Host(`mail.prg-radio.org`)"; service = "mail-jmap"; entryPoints = ["websecure"]; tls = {certresolver = "acme";}; @@ -379,7 +379,7 @@ in { # Mail web administration UI (Stalwart management) - exposed under /management mail-webadmin = { - rule = "Host(`mail.prg-radio.org`,`mta-sts.prg-radio.org`,`autoconfig.prg-radio.org`,`autodiscover.prg-radio.org`) && PathPrefix(`/management`)"; + rule = "Host(`mail.prg-radio.org`) && PathPrefix(`/management`)"; service = "mail-webadmin"; entryPoints = ["websecure"]; tls = {certresolver = "acme";};