Ports
Ports are how the outside world reaches your containers — and the number-one source of "why is this port weird" confusion. The rule is simple once you see it.
The order: "HOST:CONTAINER"
services:
web:
image: nginx:alpine
ports:
- "8080:80"
Read it left to right: your machine's port 8080 →
the container's port 80. The container thinks it's
serving on 80 (its normal port); you visit
http://localhost:8080.
The quotes matter: unquoted 8080:80 can be misread by
YAML (it's not a valid number, not quite a string).
Always quote port mappings.
Rendered (verified with Compose v5.6.0) — Compose is explicit about which end is which:
ports:
- mode: ingress
target: 80
published: "8080"
protocol: tcp
target = inside the container. published = on your
machine. When in doubt, read the rendered output.
Binding to localhost only
ports:
- "127.0.0.1:8443:443"
Three parts: HOST_IP:HOST_PORT:CONTAINER_PORT. This
publishes the port on localhost only — reachable from
your machine, invisible to the LAN. Use it for admin
interfaces and databases you don't want the whole
network poking at.
expose vs ports
expose:
- "8080"
expose declares a port for other services (documentation
plus inter-container firewalling in some setups) — it
does not publish anything to your machine. If you can
reach it from your browser, that's ports. If only other
containers need it, you usually need neither: services on
the same network reach each other's container ports
directly (Networks).
The long form
For everything the short form can't say:
ports:
- target: 80
published: 9090
protocol: tcp
mode: ingress
The classic failure: port already allocated
Two services (or a service and something on your host)
can't publish the same host port. Compose fails at up
with port is already allocated. Fix: find who's holding
it (ss -tlnp | grep 8080 on Linux, or just pick another
host port — only the published side needs to be unique;
ten containers can all use container-port 80).
Note: this one needs a running daemon to reproduce, so the message above is quoted from the Compose reference rather than a live run here.
Next: The Everyday Commands