Run an Nginx Docker Container on Port 8080
In the hello-world lab the container printed a message and stopped. Real applications are different: a web server must keep running and must be reachable from your browser. In this lab you'll run the Nginx web server in a container, publish it on port 8080, and open http://localhost:8080.
You'll learn the three docker run options you'll use almost every day: -d, --name and -p. All outputs are from a real run on Docker Engine 29.
Run the container
docker run -d --name my-nginx -p 8080:80 nginx
Docker pulled the image (seven layers this time, much bigger than hello-world), created the container, started it, and printed the new container's 64-character ID. Then it returned your prompt immediately, because of -d.
| Part | Meaning |
|---|---|
-d | Detached: run in the background and give the terminal back. Without it, the terminal stays attached to Nginx's log output until you press Ctrl+C (which also stops the container). |
--name my-nginx | A name you choose, so later commands can say my-nginx instead of an ID or a random name. |
-p 8080:80 | Publish a port: HOST_PORT:CONTAINER_PORT. Traffic to port 8080 on your computer is forwarded to port 80 inside the container. |
nginx | The image, meaning nginx:latest from Docker Hub. |
Check that it is running
docker ps
- STATUS is
Up: unlike hello-world, Nginx keeps running, because its main process is a server that waits for requests. - PORTS
0.0.0.0:8080->80/tcp: port 8080 on all of the host's IPv4 addresses forwards to port 80 in the container.[::]:8080is the same for IPv6. - COMMAND is the image's start-up command. Nginx starts with
/docker-entrypoint.sh, which then runsnginx -g "daemon off;". "daemon off" keeps Nginx in the foreground, which is exactly what keeps the container alive.
You can also ask Docker for just the port mapping:
docker port my-nginx
Open localhost:8080
Open http://localhost:8080 in your browser. You'll see the "Welcome to nginx!" page. The same request from the command line (curl -i http://localhost:8080) shows the response headers too:
The Server: nginx/1.31.8 header proves the page came from the Nginx inside the container. You never installed Nginx on Windows.
How the request reaches the container
Browser ---> localhost:8080 (your computer)
|
| Docker's port forwarding (-p 8080:80)
v
container my-nginx, port 80 ---> Nginx ---> /usr/share/nginx/html/index.html
A container has its own network namespace, with its own private IP address on Docker's internal bridge network. Nothing outside can reach it until you publish a port. The Nginx image documents that it listens on port 80 (EXPOSE 80 in its Dockerfile), but EXPOSE is only documentation. It's the -p option that actually opens the port on your machine.
Remember the order: host port first, container port second. -p 8080:80 means "my 8080 to the container's 80". Writing -p 80:8080 would forward host port 80 to port 8080 in the container, where nothing is listening.
Error: port is already allocated
A host port can be used by only one container (or program) at a time. Try to start a second Nginx on the same host port:
docker run -d --name my-nginx-2 -p 8080:80 nginx
The container was created but couldn't start. Remove it, and pick a different host port. The container port stays 80, because every Nginx container listens on its own port 80 in its own network namespace:
docker rm my-nginx-2
docker run -d --name my-nginx-2 -p 8081:80 nginx
Now http://localhost:8080 and http://localhost:8081 both returned HTTP 200: two independent web servers, from one image, on one computer. Remove the second one when you're done:
docker rm -f my-nginx-2
The same error appears if a non-Docker program (IIS, a local dev server, Skype in older days) already uses the port. Find out what is using it on Windows with netstat -ano | findstr :8080.
Stop and start: the page goes away and comes back
docker stop my-nginx
Refresh localhost:8080: the browser can no longer connect, because the process behind the port has stopped. The container still exists (docker ps -a shows it as Exited). Start it again:
docker start my-nginx
The page loads again (HTTP 200), with the same name, port mapping and settings. You don't repeat the -p option, because it was saved when the container was created. The full set of lifecycle commands is the subject of the next lab.
Common mistakes
| Symptom | Cause and fix |
|---|---|
| Container is running but localhost:8080 doesn't open | You forgot -p. Ports can't be added to an existing container: remove it and run again with -p 8080:80. |
port is already allocated | Another container or program uses that host port. Use another host port or stop the other one. |
Conflict. The container name "/my-nginx" is already in use | Names are unique. Remove the old container (docker rm -f my-nginx) or choose another name. |
| Terminal is "stuck" showing logs | You ran without -d. Press Ctrl+C (stops the container) and run again with -d. |
Interview questions
What does -p 8080:80 mean?
It publishes container port 80 on host port 8080: requests to port 8080 of the host are forwarded to port 80 inside the container. The format is host:container.
What is the difference between EXPOSE and -p?
EXPOSE in a Dockerfile only documents which port the application listens on. -p (or -P, which publishes all exposed ports to random host ports) actually opens the port on the host.
Why does the Nginx container keep running while hello-world stops?
A container lives as long as its main process. Nginx runs in the foreground (daemon off) waiting for requests; hello-world's program finishes immediately.
Summary
docker run -d --name my-nginx -p 8080:80 nginxruns Nginx in the background on host port 8080.- Port publishing is
host:container; without-pthe container isn't reachable from your browser. - One host port can be used by only one container; container ports don't conflict.
- Stopping a container closes its port; starting it again restores everything, including the mapping.
Next lab: Practise the container lifecycle: create, stop, start, restart and remove.