Idempotent UFW Configuration Over SSH (Without Losing Your Connection)

A fresh cloud server or VPS comes with every port wide open. Your provider doesn't
know what you're running, so they let everything through. This is fine for about
five minutes — until the first bot finds your IP and starts probing every exposed
service. If you're running something with a web UI (VNC, admin panels, databases),
that's an open door to anyone with a port scanner. The fix is simple: firewall
everything except SSH, and tunnel in for the rest. One port exposed, one
authentication method, one key pair. Everything else is invisible from the outside.

The problem

You want a script that guarantees a clean firewall state: SSH allowed, everything
else denied. Something you can run as part of provisioning, or re-run later if you
suspect the rules have been tampered with.

One approach is to selectively delete rules: allow SSH, then loop through ufw status numbered and delete everything that isn't SSH. This sounds clever but is
fragile in practice — you're parsing human-readable output with grep, and one
mismatched line can delete your SSH rule. We learned this the hard way when a
provisioning script kept locking us out of fresh servers.

The solution

ufw --force reset and start clean.

#!/usr/bin/env bash
set -euo pipefail

sudo ufw --force reset
sudo ufw allow OpenSSH
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw --force enable
sudo ufw status verbose

A few things to note:

  • Reset is safe. ufw reset disables the firewall and removes all rules. Disabling
    means no filtering — all traffic passes through. It does not mean "block
    everything." Your SSH session survives because there's nothing to drop it. The brief
    window of no firewall is seconds, not a risk.
  • Then build from zero. Allow SSH, deny everything else incoming, allow outgoing,
    enable. No parsing, no loops, no fragile grep chains.
  • --force suppresses confirmation prompts. Both ufw reset and ufw enable want
    interactive confirmation by default, which doesn't work over scripted SSH. Avoid yes | ufw enable — the pipe can cause SIGPIPE (exit 141) when UFW closes stdin before yes stops writing.
  • Idempotent. Run it once or ten times, you get the same result: SSH in, everything
    else out.

Opening additional ports

The firewall starts locked down, but you can add rules for services you want to
expose publicly:

sudo ufw allow 443/tcp   # HTTPS
sudo ufw allow 8080/tcp  # custom app port

These survive reboots. Re-running the reset script will wipe them — add any
permanent rules to the script itself, after the allow OpenSSH line.