Back to guides
dockerufwfirewallhardening
Server Hardening

Docker and UFW — why published ports ignore your firewall

Why Docker-published ports can bypass UFW on Linux, how to bind containers safely behind a reverse proxy, and when a hardening project is the right fix.

Key takeaway

On Linux, Docker often inserts its own firewall rules for published ports. Traffic can reach a container before it hits the UFW chains you configured. Binding app ports to localhost and exposing only a reverse proxy (80/443) is the practical fix for most single-host setups.

Docker and UFW — why published ports ignore your firewall

For operators running Docker on a Linux VPS who thought UFW was blocking a port — and discovered the internet could still reach it.

Key takeaway

On Linux, Docker often inserts its own firewall rules for published ports. Traffic can reach a container before it hits the UFW chains you configured. Binding app ports to localhost and exposing only a reverse proxy (80/443) is the practical fix for most single-host setups.

What usually goes wrong

You enable UFW, allow 22/80/443, and deny everything else. Then you publish a container with -p 8080:80 or Compose ports: ["3000:3000"]. From outside, port 3000 still answers.

That is not UFW "failing" in the usual sense. Docker manages related iptables/nftables rules for bridge networking and port publishing. Published container traffic can be diverted in ways that bypass the host INPUT path UFW users expect.

Practical pattern for one VPS

  1. Public edge: reverse proxy only on 80 and 443 (nginx, Caddy, or Traefik).
  2. App containers: no public host ports — or bind to 127.0.0.1 if the proxy runs on the host.
  3. Databases / admin UIs: private Docker networks only; never publish to 0.0.0.0.
  4. SSH: still controlled separately (keys, who can log in, ideally source limits).
  5. Cloud firewall: if your provider has one, allow only 22/80/443 at that layer too.

Example Compose idea (illustrative):

services:
  app:
    # reachable only on the Docker network / localhost
    ports:
      - "127.0.0.1:8080:80"
  proxy:
    ports:
      - "80:80"
      - "443:443"

Exact compose depends on whether the proxy is on the host or in the same Compose file.

How to check exposure

  • From another network: nmap / browser to unexpected high ports
  • On the host: ss -tulpn and review Compose ports:
  • Do not assume ufw status alone proves a Docker-published port is closed

What a hardening pass usually adds

For one Linux host this often means: agree the public surface, fix published ports, tighten SSH, document recovery, and verify after changes. That is the shape of a server hardening engagement (from £650), not a quick firewall toggle.

Practical next step

If Docker and the host firewall disagree on your VPS, start with a scoped hardening pass — or book a free 15-minute intro call to check fit first.

Need help with this?

Request Server Hardening

Ready to get started?

Get expert support for your server

Book a free 15-minute call to discuss how I can help secure and maintain your Linux infrastructure.