Learn Docker With My Newest Course

Dive into Docker takes you from "What is Docker?" to confidently applying Docker to your own projects. It's packed with best practices and examples. Start Learning Docker →

Docker Tip #59: Difference between Exposing and Publishing Ports


You can expose ports by using EXPOSE in your Dockerfile, --expose on the command line but there's also publishing ports too.

When you put EXPOSE 80 (or any port you want) in your Dockerfile that’s going to tell Docker that your container’s service can be connected to on port 80.

It doesn’t set up any networking properties. You can think of it more like a runtime configuration option that’s explicitly stated in your Dockerfile to act as nothing more than documentation on which port(s) your service listens on.

That “documentation” is presented to you when you do a docker container ls. The exposed port will be in the PORTS column, and it’s also available when you inspect a container.

You can also expose a port using --expose 80 from the docker container run --expose 80 ... command, but you would only want to do this if you don’t have EXPOSE defined in your Dockerfile, but depending on what you want to do, you may not need to expose anything.

Allowing Containers to Talk to Each Other Internally

Containers on the same network can talk to each other regardless of whether or not you exposed or published your ports back to the Docker host with -p.

This is useful for services like Postgres or Redis. These are things you typically wouldn’t want accessible from the internet, but you would want them accessible to your web application containers running on the same Docker network.

If you check out the official Docker images for Postgres and Redis, you’ll notice they set up EXPOSE 5432 (Postgres) and EXPOSE 6379 (Redis) in their Dockerfile already. They did that as a best practice to inform you on which port is being used.

Allowing Containers to Talk to Each Other + the Outside World

In this case, you have a few options:

  1. You can expose a port through your Dockerfile or use --expose and then publish it with the -P flag. This will bind the exposed port to your Docker host on a random port (verified by running docker container ls).

  2. You can expose a port through your Dockerfile or use --expose and then publish it with the -p 80:80 flag. This will bind the exposed port to your Docker host on port 80, and it expects the exposed port is 80 too (adjust as necessary with HOST:CONTAINER).

  3. You can ignore exposing anything and just use -p 80:80 in which case this doubles as both exposing AND publishing the port. Everyone from the outside world will be able to connect.

  4. You can use -p to do the same as #2 / #3 except now only your local Docker host will be able to connect, not everyone. This is useful if you had let’s say nginx running on your Docker host and you wanted it to be able to connect to a container.

What Should You Do?

I think it’s a good idea to always use EXPOSE in your Dockerfile if your service listens on a port because it explicitly states what port the service uses. Then you can optionally publish a port back to your Docker host with -p so the outside world can connect to your service.

Free Intro to Docker Email Course

Over 5 days you'll get 1 email per day that includes video and text from the premium Dive Into Docker course. By the end of the 5 days you'll have hands on experience using Docker to serve a website.