EXPOSE records which port the app listens on. It does not open, forward or publish anything.
dockerfile
EXPOSE 3000 # same as 3000/tcp
EXPOSE 3000 9229 # several ports
EXPOSE 5353/udpThe app decides the port; server.js reads $PORT and defaults to 3000. EXPOSE documents that for whoever runs the image.
Where it shows up
text
learner@pier:~/status-page$ docker image inspect status-page:0.6 --format '{{json .Config.ExposedPorts}}'
{"3000/tcp":{}}Without EXPOSE, the same command prints null.
Three ways to run it
text
learner@pier:~/status-page$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6df65503b990 status-page:0.6 "docker-entrypoint.s…" 2 seconds ago Up 2 seconds 0.0.0.0:8080->3000/tcp status
99fddfcd7640 status-page:0.6 "docker-entrypoint.s…" 8 seconds ago Up 8 seconds 0.0.0.0:32768->3000/tcp status-auto
e1dd94dc29ef status-page:0.6 "docker-entrypoint.s…" 15 seconds ago Up 15 seconds 3000/tcp status-internal| Container | Run with | PORTS | curl from the host |
|---|---|---|---|
status-internal | no flag | 3000/tcp | Fails: nothing published |
status-auto | -P | 0.0.0.0:32768->3000/tcp | localhost:32768 works |
status | -p 8080:3000 | 0.0.0.0:8080->3000/tcp | localhost:8080 works |
text
learner@pier:~/status-page$ curl localhost:3000/health
curl: (7) Failed to connect to localhost port 3000 after 0 ms: Couldn't connect to server
learner@pier:~/status-page$ docker port status-auto
3000/tcp -> 0.0.0.0:32768text
host container
-p 8080:3000 localhost:8080 ──────────────▶ :3000 node server.js
-P localhost:32768 ──────────────▶ :3000 (from EXPOSE 3000)
(none) nothing ──────╳ :3000-P is useful for quick tests. Use -p when clients need a fixed address. -p works whether or not the image has EXPOSE.
When EXPOSE is wrong
EXPOSE cannot change where the app listens. Publishing a port nobody listens on fails at connection time:
text
learner@pier:~/status-page$ docker run -d --name bad -p 8081:8080 status-page:0.6
e1dd94dc29ef1a321f7709d199f32885061b9882187edc1bdae10321dd0fa25a
learner@pier:~/status-page$ curl localhost:8081/health
curl: (56) Recv failure: Connection reset by peerKeep EXPOSE in step with the app's default port.