From c7cf21a9869a6677b26bef93f7fcdc05c5adf7cd Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Tue, 2 Jun 2026 23:18:16 +0000 Subject: [PATCH] Revert mail LAN-redirect approach; pending VIP-based redesign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pfSense NAT rdr rules added in f7cf9f07 hardcoded 10.0.20.203 (Traefik LB IP) as the redirect source. That couples mail's LAN path to Traefik's IP choice — if Traefik moves again (it just moved .200 → .203 on 2026-05-30), the mail path silently breaks. Removing the script and the matching doc paragraph; keeping the networking.md .200 → .203 staleness fix (separate correction). Follow-up: give the mail HAProxy listener a dedicated pfSense Virtual IP (IP Alias on opt1), update Technitium internal zone + WAN port-forwards to target the VIP, so mail's LAN-side path is decoupled from any other service's LB IP. --- docs/architecture/networking.md | 2 +- scripts/pfsense-nat-mail-lan-redirect.php | 90 ----------------------- 2 files changed, 1 insertion(+), 91 deletions(-) delete mode 100644 scripts/pfsense-nat-mail-lan-redirect.php diff --git a/docs/architecture/networking.md b/docs/architecture/networking.md index e9fac547..daf3b18c 100644 --- a/docs/architecture/networking.md +++ b/docs/architecture/networking.md @@ -185,7 +185,7 @@ VMs tag traffic on vmbr1 to isolate workloads. pfSense bridges VLAN 20 to the up - Only affects non-proxied domains (ha-sofia, immich, headscale, etc.) — Cloudflare-proxied domains resolve to Cloudflare IPs and are unaffected - Other clients (10.0.x.x, K8s pods) are NOT translated — they reach the public IP via pfSense outbound NAT - Config synced to all 3 Technitium instances by CronJob `technitium-split-horizon-sync` (every 6h) -- **Mail port carve-out**: the translation sends `mail.viktorbarzin.me` (and `imap.`/`smtp.`) to `.203` too, but Traefik does not serve mail ports. A pfSense NAT rdr rule redirects `10.0.20.203:{25,465,587,993}` → `10.0.20.1` (mail HAProxy) on any incoming interface, so LAN mail clients land on the right service unchanged. Script: `scripts/pfsense-nat-mail-lan-redirect.php` +- **Known mail-name collision**: the translation also sends `mail.viktorbarzin.me` (and `imap.`/`smtp.`) to `.203`, but Traefik does not listen on mail ports there. iOS Mail on Barzini WiFi silently hangs. Fix in flight: dedicated pfSense Virtual IP for the mail listener so DNS can point at a stable mail-only IP instead of relying on Traefik's LB IP. **K8s cluster DNS path**: - CoreDNS forwards `.viktorbarzin.lan` to Technitium ClusterIP (10.96.0.53) diff --git a/scripts/pfsense-nat-mail-lan-redirect.php b/scripts/pfsense-nat-mail-lan-redirect.php deleted file mode 100644 index 265b2c17..00000000 --- a/scripts/pfsense-nat-mail-lan-redirect.php +++ /dev/null @@ -1,90 +0,0 @@ - 10.0.20.1 -// (pfSense's mail HAProxy listener). But 192.168.1.x clients send to -// 10.0.20.203, not the WAN IP, so those rules don't match. -// -// This script adds 4 NAT rules that match dst=10.0.20.203 on mail ports -// and redirect them to 10.0.20.1 — same target as the public-Internet path. -// Roundcube traffic to :443 stays on Traefik (.203) untouched. -// -// USAGE (on pfSense host, via SSH as admin) -// scp infra/scripts/pfsense-nat-mail-lan-redirect.php admin@10.0.20.1:/tmp/ -// ssh admin@10.0.20.1 'php /tmp/pfsense-nat-mail-lan-redirect.php' -// -// IDEMPOTENT — removes prior copies of our rules (by descr prefix) before -// re-adding. Safe to re-run. - -require_once('/etc/inc/config.inc'); -require_once('/etc/inc/filter.inc'); - -global $config; -parse_config(true); - -$TRAEFIK_LB = '10.0.20.203'; -$MAIL_HAPROXY = '10.0.20.1'; -$DESCR_PREFIX = 'mail-lan-redirect-'; - -// One rule per port; protocols match the existing WAN-IP rules so we -// behave identically once the dst is rewritten. -$PORTS = [ - ['25', 'tcp', 'mail-lan-redirect-25 (SMTP)'], - ['465', 'tcp/udp', 'mail-lan-redirect-465 (SMTPS)'], - ['587', 'tcp', 'mail-lan-redirect-587 (submission)'], - ['993', 'tcp/udp', 'mail-lan-redirect-993 (IMAPS)'], -]; - -// Strip any prior copies we added (descr starts with our prefix). -$kept = []; -$removed = 0; -foreach (($config['nat']['rule'] ?? []) as $r) { - if (strpos($r['descr'] ?? '', $DESCR_PREFIX) === 0) { - $removed++; - continue; - } - $kept[] = $r; -} -printf("Removed %d prior copies\n", $removed); - -// Append new rules. -foreach ($PORTS as [$port, $proto, $descr]) { - $kept[] = [ - 'source' => ['any' => ''], - 'destination' => [ - 'address' => $TRAEFIK_LB, - 'port' => $port, - ], - 'ipprotocol' => 'inet', - 'protocol' => $proto, - 'target' => $MAIL_HAPROXY, - 'local-port' => $port, - 'interface' => 'wan', - 'descr' => $descr, - 'associated-rule-id'=> 'pass', - 'created' => [ - 'time' => (string)time(), - 'username' => 'pfsense-nat-mail-lan-redirect.php', - ], - 'updated' => [ - 'time' => (string)time(), - 'username' => 'pfsense-nat-mail-lan-redirect.php', - ], - ]; - printf("Added: %s (%s %s:%s -> %s:%s)\n", $descr, $proto, $TRAEFIK_LB, $port, $MAIL_HAPROXY, $port); -} - -$config['nat']['rule'] = $kept; - -write_config('NAT: LAN-side mail redirects — 10.0.20.203:{25,465,587,993} -> 10.0.20.1 for Barzini WiFi clients'); - -$rc = filter_configure(); -printf("filter_configure rc=%s\n", var_export($rc, true)); -echo "Done.\n";