Table of Contents
Understanding Port Mapping
Port mapping is what lets users and external systems reach services that run inside your containers. By default, containers are isolated from the outside world. They can listen on ports inside the container, but nothing outside can talk to those ports unless you explicitly map them.
In this chapter you will see how port mapping connects a port on your host machine to a port inside a container and how to control and inspect these mappings.
Internal Ports vs Host Ports
Every container has its own network namespace, including its own set of ports. A web server inside a container might listen on port 80, but that is an internal container port. If you open a browser on your host and navigate to http://localhost:80, the request will not reach that container unless you told Docker to map a host port to the container port when starting the container.
Port mapping establishes a relationship like:
$$\text{host\_ip:host\_port} \rightarrow \text{container\_ip:container\_port}$$
This relation is one way. You connect to your host on a port. Docker forwards the traffic to the port inside the container.
Important rule: A service inside a container is not reachable from your host unless you explicitly publish or map a container port to a host port.
Using `-p` with `docker run`
You control port mapping with the -p or --publish flag of docker run. The basic syntax most people start with is:
-p HOST_PORT:CONTAINER_PORT
For example, if you run a web server image that listens on container port 80, you might start it like this:
docker run -p 8080:80 my-web-image
This means:
- The container still listens on its internal port 80.
- Docker publishes host port 8080 and forwards traffic from
localhost:8080to port 80 inside the container.
Now when you open a browser on your host and visit http://localhost:8080, you reach the application running on port 80 inside the container.
You can repeat -p multiple times to publish several ports for the same container, for example to expose HTTP and HTTPS together.
Important rule: The syntax -p HOST_PORT:CONTAINER_PORT always uses the container side on the right and the host side on the left.
Choosing Host Ports
You are free to choose almost any host port, as long as that port is not already in use on the host. Common practices are:
Use the default service port on the host if it is free. For example, map port 80 on the host to port 80 in the container if no other web server is using port 80 on the host.
Use a higher port on the host if the default port is already used or you want to run multiple instances. For example, -p 8080:80 for the first web container and -p 8081:80 for a second one.
Docker will refuse to start a container if you try to bind to a host port that is already in use. The error usually mentions that the address is already in use. Choosing a different host port or stopping the conflicting service resolves this.
Mapping Different Container Ports
The port inside the container must match what the application actually listens on. For instance, if your application inside the container listens on port 3000, then you need to use:
-p 8080:3000
In this case, visiting http://localhost:8080 on the host forwards to container_ip:3000 inside. If you mapped the wrong container port, the connection may succeed on the host side but nothing will answer inside, so you will see connection errors or timeouts.
Knowing which port your application uses inside the container is essential. That information usually comes from the image documentation or from the application configuration.
Including Host IP in Port Mappings
The -p flag also supports an optional host IP address:
-p HOST_IP:HOST_PORT:CONTAINER_PORT
If you omit the host IP, Docker binds to all network interfaces by default. That means all IP addresses on the host will accept connections on that host port.
If you specify a particular host IP, only that IP address listens. For example:
-p 127.0.0.1:8080:80
This means:
- Only
127.0.0.1:8080on the host accepts incoming connections. - Requests from other machines to the host using its external IP will not reach the container on that port.
This approach is useful if you want to keep a service reachable only from the host itself and not from other devices on the network.
Important rule: Use 127.0.0.1:HOST_PORT:CONTAINER_PORT if you want to restrict access to a containerized service to the local machine only.
Using the Short `-P` Flag
Docker also provides a capital -P or --publish-all option when running a container. This publishes all ports that the image declares as exposed and assigns random high ports on the host.
You might see an image that specifies an exposed port in its configuration. When you run:
docker run -P my-image
Docker will pick random unused host ports and map them to the container ports that the image exposes. This can be convenient in quick experiments, but it is less predictable, because you must check which host port Docker chose.
In most real scenarios you want explicit control with -p so you know exactly where to connect.
Inspecting Port Mappings
After a container is running, you can inspect its port mappings. A common command is:
docker ps
This shows running containers and includes a column that lists which host ports are published for each container. It often looks like 0.0.0.0:8080->80/tcp or 127.0.0.1:8080->80/tcp.
The pattern is:
HOST_IP:HOST_PORT->CONTAINER_PORT/PROTOCOL
This confirms the mapping that is currently active.
For more detail you can inspect a single container:
docker inspect container_name_or_id
The output includes a NetworkSettings section with a Ports field that lists each container port and its bound host ports, if any.
If Ports shows null for a container port, that port is not published to the host. The service may still be reachable from other containers on the same docker network, but not from the outside host.
Port Mapping and Bridge Networks
In the default bridge network, containers can reach each other without port mapping by using container names and internal ports. Port mapping only matters if you want to reach the container from the host or from outside the Docker host.
So when you map -p 8080:80, you are not changing how other containers on the same bridge network talk to this container. They still use the container IP and port 80 internally. The host simply provides an additional route into that port through the mapped host port.
Understanding this distinction is important. Internal container communication uses the docker network. External access uses port mappings on the host.
Common Port Mapping Pitfalls
Beginners frequently run into a few recurring issues related to port mapping.
One common mistake is forgetting to publish any port. The container starts correctly, the application works inside, but connections from the host fail because nothing is mapped. As a general habit, when you want to access a service from the host, always check that you have a -p flag.
Another frequent problem is mapping to a wrong container port. The mapping exists, but the application listens somewhere else inside. This results in a connection without a real service responding. Checking the application documentation or running a quick check inside the container to see which port the process uses can clarify this.
A third issue is port conflicts on the host. If you already have a local web server on port 80, trying to run a Docker container with -p 80:80 will fail. Choosing a different host port, such as -p 8080:80, solves this without interfering with the existing service.
Finally, sometimes a firewall or system level network rule prevents access to a published port from other machines on the network, even though it works from localhost. Port mapping only covers the Docker side. System firewalls must also allow the traffic.
Important rule: When a container port is not reachable, always check three things in order: is it published with -p, is the container service actually listening on that port, and is there any host firewall blocking access.
Summary of Practical Usage
In everyday Docker work, port mapping is one of the most visible aspects of networking. You start a container that runs a server process, choose a host port, and connect to that port from your browser, tools, or other systems.
You use -p HOST_PORT:CONTAINER_PORT for explicit mappings, optionally restrict them with HOST_IP, and verify the results with docker ps or docker inspect. When something does not work as expected, you revisit the mapping rules, check port usage conflicts, and confirm the service configuration inside the container.
With these core ideas in place, you are ready to connect your containers to the outside world in a controlled and predictable way.