UFW Rules Not Taking Effect — Debugging Order That Works

UFW is iptables underneath. When rules seem to do nothing, the cause is one of: not enabled, wrong direction, Docker bypassing it, or a more-specific rule earlier in the chain winning.

What you'll see

Root causes

UFW isn't actually enabled (or rule direction is wrong)

ufw status must say active. 'ufw allow out' vs 'in' matter; default deny incoming must be set. The single most common miss: adding rules while inactive.

Docker inserts its own chains ahead of UFW

Published container ports (-p 8080:80) punch through UFW via the DOCKER chain — iptables -L DOCKER -n shows it. UFW rules never see that traffic.

A more specific allow rule matches first

iptables processes in order: if 'allow from 10.0.0.5' precedes 'deny 8080', that host still gets through — and looks like a broken deny.

Fix it

  1. Confirm state and effective defaults
    sudo ufw status verbose   # must say Status: active; check Default deny (incoming)
  2. See the real iptables order for your case
    sudo iptables -S | grep -E '8080|DOCKER' | head -10 && sudo iptables -L INPUT -n --line-numbers | head -15
  3. For Docker: bind or block at the right layer
    # never publish to all interfaces: -p 127.0.0.1:8080:80  # or DOCKER-USER chain rules for external traffic shaping
  4. Delete and re-add rules in the right order
    sudo ufw status numbered && sudo ufw delete <n>   # allows before denies = deny never fires; re-add deny first

Field note

Cloud security groups (AWS/Azure/DO firewalls) act BEFORE UFW — a blocked port there looks exactly like an unexplained firewall failure in-guest. Test from a truly external host: nc -vz <ip> <port> — testing from the server itself exercises loopback, not the firewall.

Common questions

Why does UFW allow Docker-published ports despite deny rules?

Docker writes its own nat/DOCKER chains that jump before the UFW chains for container traffic. UFW simply never sees those packets. Publish to 127.0.0.1, use DOCKER-USER, or run a host-level proxy instead.

How do I verify a firewall rule is really matching?

sudo iptables -L -v -n adds packet/byte counters per rule — hit the port from outside and watch the counter climb. No movement = traffic isn't reaching that rule.

Ship it right the first time

Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.

Browse the template store →

One-time. Yours to modify. Instant download from the NinjaOps template store.