Photo of the Docker logo on a building
Michael Vi/

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:


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.

image of viewing exposed ports with "docker ps"

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

image of viewing a Docker image's exposed ports with "docker inspect"

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.

image of viewing published ports with "docker ps"

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 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.


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.

Profile Photo for James Walker James Walker
James Walker is a contributor to How-To Geek DevOps. He is the founder of Heron Web, a UK-based digital agency providing bespoke software development services to SMEs. He has experience managing complete end-to-end web development workflows, using technologies including Linux, GitLab, Docker, and Kubernetes.
Read Full Bio »