Docker Port Mapping Tester

Resolve what each -p actually binds. The finding to read first is about the host firewall, because a published port is reachable whether or not ufw thinks it is.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Test. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

A mapping on every interface

Reachable from the network even with a default-deny host firewall

8080:80

A single number

That is the container port, and the host side is chosen at random

80

localhost by name

Resolved at container start, and on an IPv6-first host that means IPv6 only

localhost:8080:80

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Publishing a database with -p 5432:5432 on a public host

    It binds every interface and Docker's rules are consulted before the host firewall's, so the port is reachable from the internet even with a default-deny policy.

    Instead:Bind it: -p 127.0.0.1:5432:5432. If it must be reachable, put the restriction in the DOCKER-USER chain.

  2. Writing -p 80 and expecting port 80 on the host

    A single number is the container port. Docker assigns a random host port, which changes on every run.

    Instead:Write 80:80.

  3. Relying on EXPOSE to publish a port

    EXPOSE is documentation. It opens nothing, so the container is not reachable until something passes -p or -P.

    Instead:Publish with -p, and keep EXPOSE for describing the image.

Docker's rules sit in front of your firewall's

Docker writes into the DOCKER chain of iptables, and that chain is consulted before the rules ufw and firewalld manage. A default-deny firewall does not stop a published port.

A default-deny host still answers on every published port

This surprises people because ufw status shows the port closed and the port is open. The forwarding happens in the nat table before the filter rules the firewall manages are reached. On a machine reachable from the internet, that is a database published to the internet by a command that looked local.

Bind explicitly and the problem disappears

-p 127.0.0.1:8080:80 publishes to the loopback only, which is the right default for anything sitting behind a reverse proxy on the same host. Where a port genuinely must be public, rules belong in the DOCKER-USER chain, which Docker creates and never touches.

The left of the colon is the host

hostPort:containerPort. Reversing them is the commonest typo, and it usually produces a working container that nothing can reach, because the host side is a port nobody is trying.

A single number is not the port you think

-p 80 is the CONTAINER port, and Docker picks a random ephemeral host port for it. So the mapping changes on every run and docker port is the only way to find it. Almost nobody typing one number means that.

EXPOSE publishes nothing at all

It records which ports an image listens on, for a human reading the Dockerfile and for -P. An image with EXPOSE 80 run without -p is not reachable, and an image with no EXPOSE publishes perfectly well with -p.

Use 127.0.0.1 rather than the name

Docker resolves a hostname at container start. On a host where localhost resolves to ::1 first, the socket ends up on IPv6 only and an IPv4 client gets connection refused with nothing visibly wrong.

More docker tools

Docker Container Image Reference Parser Is that a registry or a Docker Hub user? Dockerfile Linter What this image will do to you later docker run to Kubernetes YAML And the flags that have no equivalent Docker Compose to Kubernetes And why depends_on has no equivalent Docker Logging Driver Generator json-file never rotates Dockerfile Non-Root USER Generator Numeric, or Kubernetes rejects it Docker OCI Image Labels Generator One of them actually does something Docker Hub Pull Rate Limit Calculator Counted per IP, not per person Docker Registry Storage Calculator Deleting a tag frees nothing Docker Build Context Analyzer All of it uploads before anything runs Docker Compose to docker run Converter Names stop resolving Docker Compose Version Migrator version: is obsolete now Docker Compose Network and Port Viewer Everything reaches everything Docker Command Explainer Which flags hand over the host Docker BuildKit Cache Mount Generator apt deletes the cache you just mounted Docker BuildKit Secret Mount Generator ARG is in docker history forever Docker .dockerignore Pattern Tester *.log does not match logs/app.log Docker Image Manifest Viewer unknown/unknown is not broken Docker Image Config Viewer Anyone who can pull can read your Env Docker Registry Token Decoder Check the scope before the credentials Docker HEALTHCHECK Generator Docker does nothing when it fails Docker Network Subnet Calculator 31 networks, then it stops Docker History Analyzer The rm did not save anything Docker Run to Compose Converter Some flags have no equivalent Docker CMD and ENTRYPOINT Tester Why docker stop takes ten seconds Docker -v to --mount Converter -v invents missing directories Docker Restart Policy Simulator The backoff resets after ten seconds Docker Exit Code Explainer 137 is two different problems Docker CPU Limit Converter --cpu-shares limits nothing Docker Memory Limit Calculator -m 512m allows a gigabyte Docker Compose Interpolation Tester An unset variable is an empty string Docker Environment Variable Precedence Tester Your shell does not reach the container Docker Compose Override Merge Previewer An override can add a port, never remove one Dockerfile Multi-Stage Build Analyzer Which stages reach the image Dockerignore Validator It is not .gitignore

Elsewhere on the site