Course outline · 0% complete

0/29 lessons0%

Course overview →

Ports, names, and detached mode

lesson 2-2 · ~13 min · 5/29

Long-running containers

hello-world quits instantly, but real workloads are servers that run forever. Starting one properly looks like this:

docker run -d --name web nginx
PieceEffect
-ddetached mode, runs in the background and returns the prompt
--name weba human name instead of an invented one
nginxa tiny and extremely common web server image

Without -d, the terminal is glued to the container's output. Without --name, Docker invents something like jolly_wozniak, and every later command such as docker logs web or docker stop web is easier with a name you chose.

The container is now serving a web page, and opening http://localhost in a browser still shows nothing. The reason is that a container's ports are isolated from the host until they are explicitly published, which is what the next section fixes.

Publishing ports

A port is a number from 0 to 65535 that the operating system uses to route incoming network traffic. Every server program claims a port when it starts, and the OS delivers each arriving connection to whichever program claimed the port it was addressed to. That rule is how one machine can run a web server, a database, and ssh at once without their traffic mixing. (A numbered door on a big building is a fine mental picture, but the mechanism is just that routing rule.)

nginx claims port 80, but that is port 80 inside the container's isolated network, which your browser cannot reach.

The -p flag fixes that by forwarding: traffic arriving at a chosen port on your machine is relayed to a port inside the container:

docker run -d --name web -p 8080:80 nginx

Read -p 8080:80 as host:container, left is your machine, right is inside. Traffic hitting localhost:8080 on your laptop is forwarded to port 80 in the container. Now http://localhost:8080 shows the nginx welcome page.

The order trips everyone up at first. Left side: the port outside traffic uses on your machine. Right side: the port the app inside is listening on.

browserlocalhost:8080your machine (host)8080container "web"80nginx listening on 80-p 8080:80 forwards the host door 8080 to the container door 80
-p 8080:80 in one picture. The browser knocks on the host's port 8080 and Docker forwards the traffic to port 80 inside the container.

Two containers, one image, one port conflict

Ports explain the first error every Docker user hits. Start two nginx containers:

docker run -d --name web1 -p 8080:80 nginx   # works
docker run -d --name web2 -p 8080:80 nginx   # fails

The second fails with bind: address already in use. The operating system allows exactly one program to claim a given host port, and host 8080 is already taken by the forwarding for web1. The fix is a different host port:

docker run -d --name web2 -p 8081:80 nginx   # works

Note what did not change: both containers still listen on 80 inside, because each container has its own isolated network. Container ports can repeat across containers. Host ports cannot.

Reading a published port mapping

With docker run -d -p 9000:3000 myapp and an app listening on port 3000 inside, the browser reaches it at http://localhost:9000.

-p takes host first and container second. 9000 is the port on your machine, 3000 is the port inside the container.

Side of the colonBelongs to
left, 9000the host
right, 3000the container

The browser lives on the host, so it connects to 9000 and Docker forwards to 3000. Visiting localhost:3000 reaches nothing at all, because the container's ports stay isolated until published.

Fixing a host port collision

When a second container with -p 8080:80 fails with bind: address already in use, the fix is -p 8081:80 on the second one. Host ports must be unique while container ports can repeat.

The conflict is entirely on the host side, because only one program can claim host port 8080 and the first container's forwarding already did.

ContainerHost portContainer portAllowed
first808080yes
second808080no, collision
second808180yes

Each container has its own network, so both listening on container port 80 is completely fine. Any free host port works for the second container.

The flag for host 5000 to container 3000

The flag is -p 5000:3000.

The left number is the host port that browsers and other machines use, and the right number is the port the app listens on inside the container. --publish is the long form of the same flag.

FormMeaning
-p 5000:3000host 5000 forwards to container 3000
--publish 5000:3000identical

The order is worth committing to memory, since reversing it produces a mapping that either fails or silently forwards the wrong way. Host always goes on the left of the colon.