
Exposed and Published container ports are two different but related concepts in Docker. Exposed ports are defined in your Dockerfile as simple metadata. You must publish them when your container starts if you want to enable outside access.
Exposing a Port
Ports are exposed via EXPOSE
instructions in an image’s Dockerfile:
EXPOSE 80
Exposing a port doesn’t have any immediate effect though. The statement only communicates that the application inside the container listens on port 80
. It does not bind the port to your host’s network interfaces.
As an image author, listing ports used by your workload with EXPOSE
helps users configure appropriate port forwarding rules when they start a container. This is particularly important when non-standard ports are used: while a web server can be expected to listen on port 80, users won’t be able to guess the port used by a custom socket server.
Exposed ports are visible when you list your containers with docker ps
. They’ll show up in the PORTS
column, even though they won’t actually be accessible outside the container. This gives you a simple way of checking which ports the software inside a container is listening on.
You can inspect ports exposed by an image without starting a container by using docker inspect
. Substitute your image’s tag or ID instead of demo-image
:
docker inspect --format="{{json .Config.ExposedPorts}}" demo-image
Publishing Ports
Publishing a port makes it accessible from outside the container. It lets you take a port you’ve discovered by an EXPOSE
instruction, then bind a host port to it.
Ports are exposed with the -p
flag for the docker run
command:
docker run -d -p 8080:80 httpd:latest
This command binds port 8080
on your Docker host to 80
inside your new container. Now you can visit http://localhost:8080
to access the container’s port. If you run docker ps
, you’ll see the PORTS
column now shows this mapping. The exposed container port 80
has been published to the host.
The -p
flag can be used without specifying a port to bind to:
docker run -d -p 80 httpd:latest
This variant will bind port 80 in the container to a random port on the host. You can check the port that’s been assigned by running docker ps
.
-p
also supports publishing a port to specific network interfaces:
docker run -d -p 127.0.0.1:8080:80 httpd:latest
Here the container port 80 will only be accessible via port 8080 on the host’s local loopback address. This protects your container from network calls made by your other devices.
Publishing All Exposed Ports
You can start a container with the --publish-all
flag to have Docker automatically publish all the exposed ports listed in the image’s Dockerfile:
docker run -d --publish-all httpd:latest
This will assign random free ports on your host to each exposed port in the container. Use the docker ps
command to see the port assignations that have been made. This simplifies starting a new container from an image that requires several non-standard ports to be opened.
You can combine --publish-all
with explicit -p
mappings. In this case, a mapping created by a -p
flag will override the random port assigned by --publish-all
.
When You Don’t Need to Publish a Port
You only need to publish container ports with -p
if you want to access them from your Docker host or another device on your physical network. Docker networks are the preferred alternative approach for inter-container traffic.
Containers that share a network can always communicate with each other, even if their ports have not been explicitly published.
docker network create demo-network docker run -d --network demo-network --name web web:latest docker run -d --network demo-network --name database database:latest
In this example, the web
container could connect to a MySQL server running on port 3306 in the database
container using the database:3306
address. Docker automatically sets up routing tables for the container names in the network.
Using Port Ranges
Docker can expose and publish entire port ranges when you need to have multiple ports available:
EXPOSE 8000-8100 docker run --publish-all docker run -p 6000-6100:8000-8100
In the first case, --publish-all
will assign 100 random ports on your host and map them into the container’s range. The second form explicitly binds a host range to a container range as normal. Performance can be impacted if you use a very large number of ports as an iptables
rule will be created for each one.
Summary
Exposed ports are pieces of metadata that define the ports listened to by software inside a container image. The presence of exposed ports doesn’t render them accessible on the host’s interfaces unless you manually publish them. In this sense, the verb “expose” is a misnomer, as many people assume it’s an active action when in fact it’s an informational statement. EXPOSE
should be treated as documentation whereas the -p
flag creates a functioning port mapping.
Docker does provide some extra behavior based on EXPOSE
instructions. You can view a container’s exposed ports with docker ps
irrespective of whether they’ve been published. There’s also the --publish-all
flag that publishes an image’s exposed ports to random host ports.
A container’s ports are always accessible via its own IP address, even if they’re not published. Any device which can reach the container using its Docker-assigned IP, visible in docker inspect
output, will be able to use all its listening ports.
You only need to publish ports when you want to access a container using your host’s network interface. If you’re using Docker networks, port publication isn’t necessary. Communication between containers in the same network is uninhibited, whether or not the ports involved have been exposed or published.
- › Bing Chat AI Now Has Better Search and Higher Limits
- › ChatGPT Network Error: 7 Fixes to Try
- › You Can Wash Your Motherboard In a Dishwasher (But You Probably Shouldn’t)
- › How to Know If Someone Restricted You on Instagram
- › How to Enable Dark Mode in Real Life
- › Fix: “Message Has Not Been Downloaded From the Server” on iPhone