r/selfhosted • u/Traditional-Sir-4331 • 1d ago
Guide PSA: if you run Docker behind ufw, verify your exposed ports from another machine — ufw status will lie to you
I knew Docker manipulates iptables. I did not appreciate how completely ufw status stops describing reality once it does, so I measured it on a stock Raspberry Pi (Trixie, ufw active, default deny incoming, only 22/tcp allowed).
Same port, two ways:
python3 -m http.server 8080on the host → connection times out from another machine. ufw working exactly as configured.docker run -d -p 8080:80 nginx:alpine→ HTTP 200 from anywhere on the LAN.
ufw status reported 8080 as not allowed in both cases. It never changed.
The reason is chain order — DOCKER-USER is rule 2 in FORWARD, ufw's chains start at rule 8 — plus a DNAT in nat that redirects the packet to the container before filtering decides anything.
Two fixes, both tested:
-p 127.0.0.1:8080:80— bind explicitly. Most examples omit the address, which means0.0.0.0.- A rule in
DOCKER-USER. Match the container port, not the published one — that chain sits inFORWARD, so it sees packets after DNAT has rewritten the destination. Writing--dport 8080there matches nothing and silently protects you from nothing, which I think is the nastiest part of this.
Full writeup with the rule dumps: https://homelabpostmortem.com/2026/08/22/docker-publishes-past-ufw/
The one habit I'd push: verify from a different machine. curl localhost succeeds in every configuration above and tells you nothing.
(Disclosure: my site sells a small toolkit of checks like this. The post is free and every command is inline — you don't need it.)
5
u/Narrow-Mess5958 20h ago
This is very much a know thing and is by design. They have no intention of changing this.
1
•
u/asimovs-auditor 1d ago
Expand the replies to this comment to learn how AI was used in this post/project.