How Ports in Docker Work Explained Simply

by

Faveren Caleb

How Ports in Docker Work Explained Simply

Ports in Docker control how traffic reaches a service running inside a container from your browser or any other application on the outside. Without port mapping, the container runs in an isolated network, and nothing can reach it, even if the service inside is working perfectly.

Why containers need port mapping

Containers have their own internal network. A web server running inside a container listens on port 80 of that container’s network, not on port 80 of your machine. From outside the container, that port doesn’t exist.

Port mapping creates a forwarding rule: traffic arriving on a specific port on your machine is forwarded to a specific port inside the container.

The -p flag

Port mapping is set at container startup with the -p flag:

docker run -p 8080:80 nginx

The format is always host_port:container_port, with the host on the left and the container on the right.

This command tells Docker: any traffic arriving on port 8080 on your machine should be forwarded to port 80 inside the container. Open a browser to http://localhost:8080 and you hit the NGINX server running on port 80 inside the container.

The application determines the container ports on which NGINX listens by default: 80 for HTTP, 443 for HTTPS, and so on. PostgreSQL listens on 5432 by default. The host port is your choice. You can map to any available port on the host side.

Host port vs container port

The host port must be unique on your machine. No two running containers, nor any other application, can use the same host port at the same time. If port 8080 is already in use, Docker will fail when you try to map another container to it.

The container port has no such restriction. Two containers can both listen on port 80 internally without conflicting, because each container has its own isolated network. You map them to different host ports:

docker run -p 8081:80 nginx
docker run -p 8082:80 httpd

Both containers use port 80 internally. On the host, one is reachable at 8081 and the other at 8082.

Multiple ports

A container can expose multiple ports. Map each one with its own -p flag:

docker run -p 8080:80 -p 8443:443 nginx

In a docker-compose.yml file, the same syntax applies under the ports key:

services:
  web:
    image: nginx
    ports:
      - "8080:80"
      - "8443:443"

Limiting access with an IP

By default, a mapped port listens on all network interfaces, so that any device on your network can reach it. To restrict a port to localhost only, add the IP in front:

docker run -p 127.0.0.1:5432:5432 postgres

This is useful for databases or internal services that should only be accessible from the same machine, not from other devices on the network.

Checking what’s mapped

To see the port mappings for a running container:

docker port container_name

Or check the PORTS column in docker ps. The output shows the full forwarding rule, for example, 0.0.0.0:8080->80/tcp, which means all interfaces on port 8080 forward to container port 80 over TCP.

EXPOSE vs -p

Dockerfiles sometimes include an EXPOSE instruction. This does not publish the port or make it accessible; it’s documentation that signals which port the application uses. The -p flag at runtime is what actually opens the port. If you see EXPOSE 80 in a Dockerfile and run the container without -p 8080:80, nothing will be reachable.

The Takeaway

Ports in Docker connect a port on your host machine to a port inside a container using the -p host_port:container_port syntax. The application fixes the container port; the host port is your choice and must be unique on the host. Without port mapping, a containerised service is only reachable from inside the container itself.

Leave a Comment