new-site/infra/firewall
2026-06-06 00:49:21 -05:00
..
pw-docker-fw.sh security: drop all CBC TLS suites (Qualys WEAK -> AEAD-only, still A+); sync ansible nginx templates (ciphers + ywxi CSP); capture host firewall as IaC 2026-06-06 00:49:21 -05:00
pw-firewall.nft security: drop all CBC TLS suites (Qualys WEAK -> AEAD-only, still A+); sync ansible nginx templates (ciphers + ywxi CSP); capture host firewall as IaC 2026-06-06 00:49:21 -05:00
pw-firewall.service security: drop all CBC TLS suites (Qualys WEAK -> AEAD-only, still A+); sync ansible nginx templates (ciphers + ywxi CSP); capture host firewall as IaC 2026-06-06 00:49:21 -05:00
README.md security: drop all CBC TLS suites (Qualys WEAK -> AEAD-only, still A+); sync ansible nginx templates (ciphers + ywxi CSP); capture host firewall as IaC 2026-06-06 00:49:21 -05:00

Host firewall (Infrastructure as Code)

Canonical copies of the prod app-host firewall (see docs/vm-security-hardening.md for the full rationale). These are the source of truth; the live host should match. Installed as a boot-enabled systemd service.

Files

  • pw-firewall.nft -> /etc/pw-firewall/pw-firewall.nft nftables inet pw_fw table (input hook, priority -150). Public allow-list {22, 22022, 80, 443}, a trusted_admin set allow-listing git/forgejo (3022), internal subnets + loopback fully trusted, everything else on ens18 dropped.
  • pw-docker-fw.sh -> /usr/local/sbin/pw-docker-fw.sh Adds DOCKER-USER rules so external (ens18) NEW inbound to Docker-published container ports is dropped (postgres/listmonk/api/forgejo were accidentally on 0.0.0.0); trusted_admin IPs are allow-listed to forgejo first.
  • pw-firewall.service -> /etc/systemd/system/pw-firewall.service Applies both at boot (After=docker). Also re-applied on docker restart via /etc/systemd/system/docker.service.d/pw-firewall.conf (ExecStartPost).

Install / update on the host

sudo install -D -m 0644 pw-firewall.nft  /etc/pw-firewall/pw-firewall.nft
sudo install -D -m 0755 pw-docker-fw.sh   /usr/local/sbin/pw-docker-fw.sh
sudo install -D -m 0644 pw-firewall.service /etc/systemd/system/pw-firewall.service
sudo systemctl daemon-reload
sudo systemctl enable --now pw-firewall.service

Add / remove a trusted admin IP (for git push over :3022)

sudo nft add element inet pw_fw trusted_admin { <IP> }      # live
# then add <IP> to TRUSTED_ADMIN in pw-docker-fw.sh + the set in pw-firewall.nft
# and re-run: sudo systemctl restart pw-firewall.service

Safety

Roll out with an auto-rollback timer (setsid sh -c 'sleep 300; nft delete table inet pw_fw; iptables -F DOCKER-USER; ...') so a bad rule can't lock you out; cancel it only after verifying SSH + git still work from off-network.