Stage 4 · Provision
Networking, Storage & Compose Deep Dive
Published Port Path
Trace -p traffic through NAT rules, localhost binding, IPv6 listeners, and container service ports.
Port Publishing Mechanics
When you publish a port with -p, Docker creates iptables rules that route traffic from the host port to the container port. Understanding this path helps you debug connectivity issues, firewall problems, and performance bottlenecks.
# Publish host port 8080 to container port 80
docker run -d -p 8080:80 nginx
# Traffic path:
# 1. Client connects to host:8080
# 2. iptables DNAT rule rewrites destination to container-ip:80
# 3. Bridge network forwards to container
# 4. Container receives on port 80
# Verify with iptables
iptables -t nat -L -n | grep 8080Docker uses iptables DNAT (Destination NAT) to redirect traffic. The rule matches the host port and rewrites the destination to the container's IP and port.
NAT Rules
# View Docker's iptables rules
iptables -t nat -L -n -v
# Look for DOCKER chain
iptables -t nat -L DOCKER -n
# Check port forwarding
iptables -t nat -L DOCKER -n | grep 8080
# DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80
# Check if port is actually listening
ss -tlnp | grep 8080
lsof -i :8080Docker creates iptables rules in the DOCKER chain. The DNAT rule rewrites the destination address. If the port is not accessible, check these rules first.
Localhost Binding
# Bind to all interfaces (default)
docker run -d -p 8080:80 nginx
# Accessible from any network interface
# Bind to localhost only
docker run -d -p 127.0.0.1:8080:80 nginx
# Only accessible from localhost
# Bind to a specific interface
docker run -d -p 192.168.1.100:8080:80 nginx
# Only accessible from that interface
# Verify binding
ss -tlnp | grep 8080
# tcp LISTEN 0.0.0.0:8080 — all interfaces
# tcp LISTEN 127.0.0.1:8080 — localhost onlyWithout an interface prefix, Docker binds to 0.0.0.0 (all interfaces). Use 127.0.0.1 for development tools that should not be network-accessible.
IPv6
# Enable IPv6 in Docker daemon
# /etc/docker/daemon.json:
# { "ipv6": true, "fixed-cidr-v6": "fd00::/80" }
# Publish on IPv6
docker run -d -p [::]:8080:80 nginx
# Access via IPv6
curl http://[::1]:8080
# Check IPv6 listeners
ss -tlnp | grep 8080
# tcp LISTEN [::]:8080Docker supports IPv6 port publishing. Use [::] to listen on all IPv6 interfaces, or [::1] for localhost IPv6 only. IPv6 is disabled by default in Docker.
Container Service Ports
# Web servers
docker run -d -p 80:80 nginx # HTTP
docker run -d -p 443:443 nginx # HTTPS
# Databases
docker run -d -p 5432:5432 postgres # PostgreSQL
docker run -d -p 3306:3306 mysql # MySQL
docker run -d -p 27017:27017 mongo # MongoDB
# Development tools
docker run -d -p 3000:3000 myapp # Custom apps
docker run -d -p 8080:8080 adminer # Admin UIsMap standard service ports to predictable host ports. This makes it easy to access services and configure firewalls. Use different host ports when running multiple instances.
Port Troubleshooting
# 1. Check if container is running
docker ps
# 2. Check container port mapping
docker port <container>
# 3. Check if port is listening on host
ss -tlnp | grep <port>
lsof -i :<port>
# 4. Check iptables rules
iptables -t nat -L DOCKER -n | grep <port>
# 5. Test connectivity from host
curl -v http://localhost:<port>
# 6. Test from inside the container
docker exec <container> curl -v http://localhost:<container-port>
# 7. Check container logs
docker logs <container>Follow this debugging sequence: verify the container is running, check port mapping, verify the port is listening, check firewall rules, test connectivity, test from inside the container, and check logs.
docker port <container> shows all published ports. It is the quickest way to see the port mapping without parsing docker inspect output.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.