4.2.10.2 EXPOSE Container Port
A focused guide to EXPOSE Container Port, connecting core concepts with practical Docker and container operations.
EXPOSE container port refers specifically to the port number as seen from inside the container — the port the application itself is actually bound to — which is distinct from, and does not need to match, whatever port it might eventually be mapped to on the host.
The Container's Own Port Perspective
The port declared by EXPOSE, and the port an application actually listens on, exist entirely within the container's own network namespace, independent of how that port might later be exposed externally.
EXPOSE 8080
CMD ["node", "server.js"]
If server.js is written to listen on port 8080, this EXPOSE declaration accurately documents the container-side port the application actually uses.
Container Port vs. Host Port in Practice
When publishing this port to the host, the host-side port number can be entirely different from the container-side port, with Docker handling the translation between them.
docker run -p 3000:8080 myapp
Here, the application inside the container still listens on 8080, exactly as declared; externally, it is reachable on the host at port 3000 instead.
Why This Distinction Matters for Multiple Containers
Because each container has its own isolated network namespace, multiple containers can all use the identical container-side port internally — say, 8080 — without conflict, since conflicts at the host level only arise from the host-side port mappings, not from the container-side ports themselves.
docker run -p 3000:8080 app-a:1.0
docker run -p 3001:8080 app-b:1.0
Both containers listen on 8080 internally without any conflict, since each one's host-side mapping is distinct.
Confirming the Container-Side Port Directly
The actual port an application is listening on inside a running container can be confirmed directly, independent of any host-side mapping that might be in effect.
docker exec myapp ss -tlnp
Why Understanding the Container Port Perspective Matters
Recognizing that EXPOSE documents the container's own internal port, not any externally visible port, clarifies why host-side port mappings can vary freely between deployments without requiring any change to the image or its EXPOSE declarations.