Docker port publishing: 127.0.0.1, 0.0.0.0 and ufw

Who can reach a container's port depends on how it is published, not on ufw. Switch between an unpublished port, one published on every address and one published on 127.0.0.1, with ufw on or off, and see who gets through.

Published 13 October 2026

A server with ufw set to deny incoming traffic looks closed. Then a Compose file publishes a database port, and the database is reachable from the internet anyway.

This explainer shows the three places a request can come from, and how each way of publishing a port changes which of them reach the container.

Explore it

Publish the port
ufw, deny incoming
Who reaches the container's port Example values
  • The internetBlocked The port is not published.
  • The Docker hostReaches The host reaches every container port on its bridge networks.
  • A container on the same networkReaches Containers on the same network reach each other's ports by name.

Container, port 80

Port mapping: No ports: entry

ufw: off

From the internet: Blocked. From the host: Reaches. From the same network: Reaches.

Step by step

  1. Compose puts the services of a project on their own bridge network. Every port of a container on that network is reachable from the Docker host and from the other containers on the same network, by service name, whether or not it is published.

    Nothing outside the server reaches it: without ports:, the container has no address on the internet.

  2. ports: ["8080:80"] has no host address, so Docker publishes the port on all of them: 0.0.0.0 and [::]. Anyone who can reach the server's public IP on port 8080 now reaches the container's port 80.

    That is what a port mapping copied from a README usually does.

  3. Turn on ufw with its default "deny incoming" and the port stays open. Docker routes traffic to a published port with its own packet-filtering rules, before ufw's rules are applied, so ufw never sees it.

    To filter a published port, use Docker's DOCKER-USER chain or the provider's firewall, or don't publish it on a public address at all.

  4. ports: ["127.0.0.1:8080:80"] publishes the port on the loopback address only. The host reaches it at localhost:8080; the internet does not, with or without ufw.

    Put a reverse proxy in front of what should be public, and reach admin interfaces through an SSH tunnel: ssh -L 8080:127.0.0.1:8080 <user>@<server>.

Example values Ports 8080 and 80 are example values.

What the diagram shows

The diagram shows a container with port 80, a port mapping, ufw, and three sources: the internet, the Docker host and another container on the same network. Each source is marked "reaches" or "blocked", with the reason.

The controls choose how the port is published (not published, on every address, on 127.0.0.1) and whether ufw denies incoming traffic. Only publishing on every address lets the internet in, and ufw does not change that; the host and the containers on the same network always reach the port.

Try it in the tool

Open Docker Compose Analyzer

What this does not cover

Covers Docker Engine's default bridge networking with its default iptables rules on Linux. Rootless Docker, Docker Desktop, the host network mode and custom firewall setups behave differently.

Sources

How ANAROQ sources its data and numbers is described in the methodology. Read the methodology

All explainers