Skip to content

Port Mapping


A service can be running perfectly inside a container and still be completely unreachable from outside. That’s because a container’s ports are isolated from the host and external network by default. In this article, we’ll see how Docker’s port mapping connects the outside world to services running inside containers—and what happens behind the scenes when a request travels through that path.

What is Port Mapping?

Port mapping is the process of making a port inside a Docker container accessible through a port on the Docker host.

A container can run a service such as nginx and listen on port 80 inside the container. However, that does not automatically mean that other machines can connect to that service.

For example, if nginx is listening on:

Container
    ↓
TCP :80

we can publish that port on the Docker host:

Docker Host :8080
        ↓
Container :80

The Docker command for this is:

docker container run -d -p 8080:80 nginx

Here:

8080:80
│    │
│    └── Container port
└─────── Host port

This means:

Connections to port 8080 on the Docker host are forwarded to port 80 of the container.

Port mapping is also commonly called port publishing.

Why Port Mapping is Useful?

Containers are isolated from the host and from external networks by default. This is useful because applications inside containers don’t automatically expose their ports to the outside world.

Port mapping provides a controlled way to expose a containerized service.

Common use cases include:

  • Exposing a web application running inside a container.
  • Accessing an nginx or Apache web server from another machine.
  • Exposing an API running inside a container.
  • Connecting to a development database from the host.
  • Running multiple containers that use the same internal port.
  • Controlling which host ports are exposed externally.

For example, you can run two nginx containers that both listen on port 80 internally:

Host :8080  →  Container A :80
Host :8081  →  Container B :80

The containers don’t need different internal ports because their network namespaces are separate.

How to Port Map Containers?

The basic syntax is:

docker container run -p <host-port>:<container-port> <image>

For example:

docker container run -d -p 8080:80 nginx

This publishes port 80 inside the container on port 8080 of the Docker host.

You can verify the published port with:

docker container ls

You should see something similar to:

PORTS
0.0.0.0:8080->80/tcp

You can also inspect the container:

docker container inspect <container-id>

Or extract the port mapping:

docker container port <container-id>

You may get:

80/tcp -> 0.0.0.0:8080

Binding to a Specific Host Address

By default:

-p 8080:80

usually publishes the port on all host interfaces.

You can explicitly specify the host address:

docker container run -d -p 0.0.0.0:8080:80 nginx

Or bind it only to localhost:

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

The second example means that the service can be accessed from the Docker host itself, but it isn’t directly published on the host’s external network interfaces.

Note

Publishing a port does not automatically make the service reachable from every network. Host firewalls, cloud security groups, routing, and other network policies can still block the connection.

What Happens in the Networking Stack?

When you run:

docker container run -d -p 8080:80 nginx

Docker creates a network path between the host’s port 8080 and the container’s port 80.

A simplified view looks like this:

Other Machine
      |
      | TCP :8080
      ↓
Docker Host
      |
      | Port publishing / NAT
      ↓
Docker bridge network
      |
      ↓
Container
      |
      | TCP :80
      ↓
nginx

The container normally has its own network namespace and receives its own IP address on the Docker bridge network.

For example:

Docker Host
192.168.1.10

Container
172.17.0.2

nginx listens on:

172.17.0.2:80

When Docker publishes:

192.168.1.10:8080 → 172.17.0.2:80

a connection arriving at the host’s port 8080 is translated and forwarded toward the container.

On Linux, Docker commonly implements this using the host’s networking facilities, including network namespaces, virtual Ethernet interfaces, bridges, routing, and packet-filtering/NAT rules.

The exact implementation can vary depending on the Docker networking configuration, operating system, and Docker version, so it is better to think of port publishing as a logical host-port → container-port forwarding mechanism rather than relying on one specific kernel rule.

Port Mapping: Working Example with nginx

Let’s see this in action using an nginx container.

Step 1: Start nginx Without Port Mapping

Start an nginx container without publishing any ports:

docker container run -d --name nginx1 nginx

Check the running container:

docker container ls

You will notice that there is no published port in the PORTS column.

nginx is still listening on port 80 inside the container, but that port has not been published on the Docker host.

Step 2: Get the Container IP

We can inspect the container:

docker container inspect nginx1

Or extract its IP address directly:

docker container inspect \
  --format '{{.NetworkSettings.IPAddress}}' \
  nginx1

Suppose Docker gives us:

172.17.0.2

We can verify that nginx is responding from the Docker host:

curl http://172.17.0.2

You should receive the default nginx HTML response.

However, this does not mean that another machine on the network can access 172.17.0.2.

Step 3: Try From Another Machine

Suppose the Docker host has this IP:

192.168.1.10

From another machine, you might try:

curl http://172.17.0.2

This will normally fail.

Why?

Because 172.17.0.2 is the container’s address on Docker’s private bridge network. It is not the Docker host’s LAN address, and machines outside the Docker host generally don’t have a route to that private container network.

This is an important distinction:

Container IP
172.17.0.2
     ↑
Private Docker network

Docker Host IP
192.168.1.10
     ↑
Reachable from LAN

Simply knowing the container IP does not publish the service externally.

Step 4: Start nginx With Port Mapping

Let’s remove the first container:

docker container rm -f nginx1

Now start another nginx container and publish port 80:

docker container run -d \
  --name nginx2 \
  -p 8080:80 \
  nginx

Check the container:

docker container ls

You should see something similar to:

PORTS
0.0.0.0:8080->80/tcp

This tells us:

Docker Host :8080
       ↓
Container :80
       ↓
nginx

Step 5: Inspect the Container

We can still retrieve the container IP:

docker container inspect \
  --format '{{.NetworkSettings.IPAddress}}' \
  nginx2

Suppose it returns:

172.17.0.2

Notice that the container IP is still a private Docker-network address.

The important difference is that we have now published the container’s port.

Step 6: Access From Another Machine

From another machine on the same network, use the Docker host’s IP and the published port:

curl http://192.168.1.10:8080

The request travels approximately like this:

Other Machine
192.168.1.20
      |
      | HTTP :8080
      ↓
Docker Host
192.168.1.10:8080
      |
      | Port publishing
      ↓
Docker bridge
172.17.0.2:80
      |
      ↓
nginx

This time, the request can reach the Docker host, where Docker forwards the traffic to the container.

Important

Do not use the container IP when testing access from another machine. Use the Docker host’s reachable IP address plus the published host port.

In this example:

❌ http://172.17.0.2:80

✅ http://192.168.1.10:8080

If the second request still fails, check the Docker host’s firewall, cloud security-group rules, network routing, and whether nginx is actually running.

The Complete Picture

Without port mapping:

Other Machine
      |
      X
      |
Docker Host
      |
      └── Docker Bridge → Container :80

With port mapping:

Other Machine
      |
      | :8080
      ↓
Docker Host :8080
      |
      | Docker port publishing
      ↓
Container :80
      |
      ↓
nginx

The key idea is simple:

A container port being open is not the same as a host port being published.

The container can have a service listening on port 80 while that service remains inaccessible from outside the Docker host. Port mapping creates the path that allows external clients to reach that service through a port on the host.

Last updated on