✦ For everyone, free.

Practical knowledge for real and everyday life

Home

20.1.1.4 Port Publishing Basics

A focused guide to Port Publishing Basics, connecting core concepts with practical Docker and container operations.

Port publishing connects a port on the Docker host machine to a port inside a container. Without publishing, a container's network ports are only accessible from within Docker's internal network — other containers on the same network can reach them, but processes on the host and external machines cannot. Publishing a port creates a mapping that forwards traffic arriving at a host port to the corresponding port inside the container.

The -p Flag

Port publishing is done with the -p flag on docker run:

docker run -d -p 8080:80 nginx:latest

The format is: -p <host_port>:<container_port>

In this example:

  • 8080 is the port on the host machine where traffic arrives.
  • 80 is the port inside the container where the application is listening.

After this command, any HTTP request sent to http://localhost:8080 on the host is forwarded to the nginx process listening on port 80 inside the container.

How Port Mapping Works

Browser :8080 Host port 8080 :80 Container port 80

Docker sets up iptables rules on the host to forward incoming traffic from the host port to the container's network namespace. This forwarding is transparent to the application inside the container, which only sees connections arriving on port 80.

Publishing Multiple Ports

Use multiple -p flags to publish several ports:

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

This publishes both HTTP (80) and HTTPS (443) ports from the container to ports 8080 and 8443 on the host.

Binding to a Specific Host IP

By default, Docker binds to all host network interfaces (0.0.0.0), making the port reachable from any network the host is connected to. To restrict access to a specific interface:

docker run -d -p 127.0.0.1:8080:80 nginx:latest

This binds only to localhost. External machines on the network cannot reach port 8080; only processes on the same host can.

To bind to a specific network interface IP:

docker run -d -p 192.168.1.100:8080:80 nginx:latest

Publishing to a Random Host Port

If you let Docker choose the host port, it picks a random available port from the ephemeral port range:

docker run -d -p 80 nginx:latest

Only the container port is specified. Docker assigns a random host port. To find which port was assigned:

docker port my_container 80

Or view it in docker ps output under the PORTS column.

The --publish-all Flag

The --publish-all (or -P) flag publishes all exposed ports declared in the image to random host ports:

docker run -d -P nginx:latest

Every port declared with EXPOSE in the Dockerfile is published to a random host port. This is useful for quick testing without specifying port numbers manually.

EXPOSE vs. -p

A common source of confusion is the distinction between the Dockerfile EXPOSE instruction and the -p flag:

  • EXPOSE in a Dockerfile is documentation — it declares which port the application inside the image listens on. It does not publish the port to the host. Without -p at runtime, the port is accessible only from within Docker networks.
  • -p at runtime is what actually publishes the port — it creates the host-to-container port mapping that makes the service reachable from outside Docker.

EXPOSE informs users and tools (like Docker Compose and --publish-all) about intended ports. -p is what opens them to external traffic.

Viewing Published Ports

docker ps

The PORTS column shows all published mappings:

PORTS
0.0.0.0:8080->80/tcp, 0.0.0.0:8443->443/tcp

To see ports for a specific container:

docker port my_container
80/tcp -> 0.0.0.0:8080
443/tcp -> 0.0.0.0:8443

UDP Ports

By default, -p publishes TCP ports. To publish a UDP port:

docker run -d -p 5353:53/udp dns_server

To publish both TCP and UDP on the same port number:

docker run -d -p 53:53/tcp -p 53:53/udp dns_server

No Port Published: Internal-Only Services

Containers that do not need to be accessed from outside Docker (for example, a database used only by another container on the same network) should not have ports published. Containers on the same Docker network can reach each other directly by container name and port without any host-level publishing:

docker network create app_network
docker run -d --name db --network app_network postgres:15
docker run -d --name web --network app_network -p 8080:80 my_app

The web container can connect to db:5432 directly. No port from db needs to be published to the host, which reduces the host's network attack surface.