Legendary Arena Lab

UFW Firewall

wiki

UFW Firewall

Migration in progress. api.legendary-arena.com and its PostgreSQL are moving off Render onto a self-hosted DigitalOcean Ubuntu droplet fronted by Cloudflare, per docs/PLAN.md . Until decommission, Render stays warm as the rollback target.

Summary

UFW Firewall sets the droplet’s inbound perimeter to default-deny, then opens only SSH, HTTP, and HTTPS. It is a Phase 1 hardening step that runs after the SSH daemon is locked down and before web traffic is fronted by Cloudflare.

Mechanics

The entity is owned by infra/scripts/06-ufw.ps1 , an idempotent PowerShell provisioner that runs under Set-StrictMode -Version Latest and $ErrorActionPreference = 'Stop' and requires root (per docs/PLAN.md ).

  1. Root gate. Require-Root throws if the process is not uid 0.
  2. SSH port resolution. Reads $SshPort from the SSH_PORT environment variable, defaulting to 22 when unset.
  3. Default policy. ufw default deny incoming and ufw default allow outgoing — deny everything inbound, permit everything outbound.
  4. Allow rules. Opens SSH on $SshPort/tcp, then 80/tcp and 443/tcp. The allow-SSH rule is issued before the firewall is enabled so the default-deny policy never strands the live session.
  5. Enable and report. ufw --force enable activates the ruleset non-interactively, then ufw status verbose prints the result.

It is idempotent because UFW rules are declarative — re-running converges to the same ruleset rather than stacking duplicates.

Interactions

  • SSH Hardening . The allow-SSH rule must match the port the hardened daemon actually listens on; if that port is non-standard, pass the same value here via SSH_PORT.
  • Cloudflare TLS . This page opens 443 wide; the Cloudflare TLS step (script 21) later narrows the 443 rule to Cloudflare’s published IP ranges so origin HTTPS is reachable only through the CDN.
  • Fail2ban and Unattended Upgrades . A complementary host-security layer — UFW blocks unlisted ports while fail2ban bans brute-force attempts on the allowed ones.

Edge Cases

  • Order-of-operations lockout. Enabling default-deny before the allow-SSH rule would drop your live session. The script issues the SSH allow first for exactly this reason — preserve that order in any manual re-run.
  • Port mismatch with the hardened daemon. If SSH runs on a non-standard port, you must export SSH_PORT to match SSH Hardening ; otherwise UFW opens the wrong port and blocks logins.
  • 443 is opened broadly here. Until Cloudflare TLS tightens it, the origin’s HTTPS port is reachable from anywhere, not just Cloudflare. That is expected at this stage, not a final state.
  • Outbound is unrestricted. default allow outgoing means the host can reach anything egress-side; this firewall governs inbound only.

Execute

sudo pwsh -File infra/scripts/06-ufw.ps1

# Override the SSH port to match a non-standard hardened daemon:
sudo SSH_PORT=22 pwsh -File infra/scripts/06-ufw.ps1

Verify

sudo ufw status verbose
# expected: Status: active
#           Default: deny (incoming), allow (outgoing)
#           22/tcp   ALLOW IN  Anywhere
#           80/tcp   ALLOW IN  Anywhere
#           443/tcp  ALLOW IN  Anywhere

References