# Hetzner Cloud firewall rules, keyed by firewall name. Imported by # machines/control/configuration.nix and fed to cnx.hetznerFirewall.firewalls. # # Public SSH (22) is intentionally absent: admin access rides the ZeroTier mesh # (inside UDP 9993), with emergency-access as the console fallback. let world = [ "0.0.0.0/0" "::/0" ]; zerotier = { direction = "in"; protocol = "udp"; port = "9993"; source_ips = world; description = "ZeroTier"; }; ping = { direction = "in"; protocol = "icmp"; source_ips = world; description = "ICMP (ping / PMTUD)"; }; # Public mail ports for mx1 (MX for cnx.email). 25 is server-to-server # delivery; 587/465 are client submission; 143/993 are IMAP. 443 serves only the # MTA-STS policy (https://mta-sts.cnx.email/.well-known/mta-sts.txt); the cert # itself uses ACME DNS-01 so port 80 stays closed. Admin still rides the mesh. mailPort = port: description: { direction = "in"; protocol = "tcp"; inherit port; source_ips = world; inherit description; }; mailRules = [ (mailPort "25" "SMTP (inbound mail)") (mailPort "587" "Submission (STARTTLS)") (mailPort "465" "Submission (implicit TLS)") (mailPort "143" "IMAP (STARTTLS)") (mailPort "993" "IMAP (implicit TLS)") (mailPort "443" "MTA-STS policy (HTTPS)") ]; # web01 is a public reverse proxy with TLS termination. 443 serves the proxy; # 80 only carries Caddy's HTTP->HTTPS redirect (the cert uses ACME DNS-01, not # HTTP-01). Admin rides the mesh. webRules = [ { direction = "in"; protocol = "tcp"; port = "80"; source_ips = world; description = "HTTP (redirect to HTTPS)"; } { direction = "in"; protocol = "tcp"; port = "443"; source_ips = world; description = "HTTPS (reverse proxy / TLS termination)"; } ]; dnsRules = [ { direction = "in"; protocol = "udp"; port = "53"; source_ips = world; description = "DNS (UDP)"; } { direction = "in"; protocol = "tcp"; port = "53"; source_ips = world; description = "DNS (TCP)"; } zerotier ping ]; in { "clan-control" = [ zerotier ping ]; "clan-ns1" = dnsRules; "clan-ns2" = dnsRules; "clan-mx1" = mailRules ++ [ zerotier ping ]; "clan-web01" = webRules ++ [ zerotier ping ]; }