Stage 4 · Provision
Running & Networking Containers
Ports
Publish ports with -p, inspect listeners, distinguish container ports from host ports, and avoid collisions.
Container vs Host Ports
Containers have their own network namespace with their own port range. A container listening on port 8080 is only accessible from inside the container unless you publish that port to the host. Publishing maps a host port to a container port, making the service accessible from outside Docker.
# nginx listens on port 80 inside the container
docker run -d --name web nginx
# From the host, port 80 is NOT accessible
curl http://localhost:80 # Connection refused
# Inspect the container's port mapping
docker port web
# No ports publishedBy default, containers have no published ports. The container's port 80 exists only in its network namespace. You must explicitly publish ports with -p to make them accessible from the host.
Publishing Ports
The -p flag maps a host port to a container port. The format is -p hostPort:containerPort. You can also bind to specific interfaces and use random host ports.
# Map host port 8080 to container port 80
docker run -d -p 8080:80 nginx
curl http://localhost:8080 # Works
# Map to a specific interface
docker run -d -p 127.0.0.1:8080:80 nginx
# Only accessible from localhost
# Random host port
docker run -d -p 80 nginx
docker port <container-id> # Shows the random port
# Map a range of ports
docker run -d -p 5000-5010:5000-5010 myappThe host port comes first, the container port second. -p 8080:80 means traffic to host:8080 goes to container:80. Without an interface prefix, Docker binds to all interfaces (0.0.0.0).
Port Collisions
Two containers cannot publish the same host port. If container A uses -p 8080:80 and container B tries -p 8080:80, Docker will fail with an address already in use error. Plan your port allocation or use random ports for services that do not need predictable ports.
# First container uses port 8080
docker run -d -p 8080:80 --name web1 nginx
# Second container uses a different port
docker run -d -p 8081:80 --name web2 nginx
# Or use random ports for services behind a load balancer
docker run -d -p 80 --name web3 nginx
docker port web3 # e.g., 0.0.0.0:32768->80/tcpRandom ports are useful when multiple instances of the same service run simultaneously. The load balancer or service mesh discovers the actual port mapping.
Inspecting Port Mappings
# Show port mappings for a container
docker port web1
# Show all port mappings in docker ps
docker ps --format "table {{.Names}} {{.Ports}}"
# Inspect full network settings
docker inspect web1 --format '{{json .NetworkSettings.Ports}}'
# Check what is listening on the host
lsof -i :8080
netstat -tlnp | grep 8080docker port shows the published ports. docker inspect shows the full network configuration including the container's internal IP and port bindings.
EXPOSE Instruction
The EXPOSE instruction in a Dockerfile documents which ports the container uses. It does not publish the port — it is metadata for documentation and tooling. You still need -p at runtime to actually publish the port.
# This documents that the app listens on port 3000
EXPOSE 3000
# But you still need -p at runtime:
# docker run -p 3000:3000 myapp
# EXPOSE UDP ports
EXPOSE 5353/udp
# EXPOSE multiple ports
EXPOSE 80 443 8080EXPOSE has no runtime effect. It tells other developers and tools which ports the application uses. Some orchestration tools use EXPOSE to automatically configure networking.
Multiple Ports
Containers can publish multiple ports. This is common for applications that serve HTTP and HTTPS, or for microservices that expose multiple protocols.
# Multiple -p flags for multiple ports
docker run -d \
-p 80:80 \
-p 443:443 \
-p 8080:8080 \
--name webserver \
nginx
# Verify all ports are published
docker port webserver
# 80/tcp -> 0.0.0.0:80
# 443/tcp -> 0.0.0.0:443
# 8080/tcp -> 0.0.0.0:8080Each -p flag creates one port mapping. You can have as many as needed. Docker creates iptables rules for each mapping to route traffic from the host to the container.
Use -p 127.0.0.1:8080:80 to restrict access to localhost only. This prevents the container from being accessible from the network. Useful for development databases and admin interfaces.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.