Introduction

Docker container networking errors occur when containers cannot communicate with each other, the host system, or external networks due to misconfigured networks, DNS resolution failures, port mapping issues, or firewall rules blocking traffic. Docker provides multiple networking drivers (bridge, host, overlay, macvlan, none) each with different use cases and failure modes. Common causes include containers on different networks unable to communicate, DNS resolution failing within containers, port conflicts on host, iptables rules blocking container traffic, overlay network encryption issues, MTU mismatches causing packet fragmentation, network namespace isolation problems, and Docker daemon network configuration errors. The fix requires understanding Docker networking architecture, Linux networking fundamentals, NAT/bridge operations, and debugging tools. This guide provides production-proven troubleshooting for Docker networking issues across single-host and Swarm deployments.

Symptoms

  • docker run fails with Error starting userland proxy: listen tcp: bind: address already in use
  • Container cannot resolve DNS names: nslookup: can't resolve 'google.com'
  • Containers on same network cannot ping each other
  • curl: (7) Failed to connect to <container> port 80: Connection refused
  • External clients cannot access published ports
  • Overlay network shows encryption: unencrypted mismatch
  • docker network inspect shows empty Containers list
  • Container IP not reachable from host or other containers
  • Intermittent connection timeouts between containers
  • no route to host errors from within containers
  • Port published but returns Connection refused
  • DNS round-robin not working for service discovery

Common Causes

  • Containers attached to different networks (isolated by default)
  • Docker DNS resolver (127.0.0.11) not working
  • Host firewall (ufw/iptables) blocking Docker traffic
  • Port already bound on host (conflict with existing service)
  • Docker daemon not restarted after network config change
  • Overlay network requires Swarm mode, not available in standalone
  • MTU mismatch between Docker networks and physical interfaces
  • docker0 bridge misconfigured or missing
  • IP tables manipulation disabled Docker's NAT rules
  • Container network namespace not properly isolated
  • Published port bound to 127.0.0.1 instead of 0.0.0.0
  • Network plugin (CNI) not loaded or crashed

Step-by-Step Fix

### 1. Diagnose container connectivity

Check container network configuration:

```bash # List all networks docker network ls

# Output: # NETWORK ID NAME DRIVER SCOPE # abc123456789 bridge bridge local # def123456789 host host local # ghi123456789 none null local # jkl123456789 mynet bridge local

# Inspect specific network docker network inspect mynet

# Shows: # - Network subnet and gateway # - Connected containers # - IP addresses assigned # - DNS configuration

# Check container's network settings docker inspect <container-id> --format '{{.NetworkSettings.Networks}}' docker inspect <container-id> --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'

# Get container IP docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container>

# Check which network a container is on docker inspect -f '{{range $key, $value := .NetworkSettings.Networks}}{{$key}}{{end}}' <container> ```

Test container connectivity:

```bash # Exec into container and test docker exec -it <container> sh # Inside container: ping 8.8.8.8 # Test basic connectivity ping google.com # Test DNS resolution curl http://other-container:80 # Test service discovery

# Test from host to container CONTAINER_IP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container>) curl http://$CONTAINER_IP:80

# Test container-to-container on same network docker exec <container1> ping <container2-name> # Should resolve via Docker DNS

# Test with nc (netcat) for port connectivity docker exec <container> nc -zv other-container 80 docker exec <container> nc -zv 172.18.0.5 80 ```

Check Docker network internals:

```bash # Check docker0 bridge ip addr show docker0 # Should have IP like 172.17.0.1/16

# Check iptables rules for NAT iptables -t nat -L -n | grep -E "docker|MASQUERADE"

# Check Docker chains iptables -L DOCKER -n -v iptables -L DOCKER-USER -n -v

# Check if Docker is managing iptables # If iptables -L shows no Docker chains, Docker may not be managing firewall

# Check network namespaces ls -la /var/run/docker/netns/ # Should show namespace for each container

# Inspect namespace ip netns list # Or with Docker namespaces: for f in /var/run/docker/netns/*; do ip netns exec $(basename $f) ip addr; done ```

### 2. Fix DNS resolution issues

Docker's embedded DNS:

```bash # Docker provides embedded DNS at 127.0.0.11 inside containers # This handles: # - Container name resolution # - Service discovery (Swarm) # - External DNS forwarding

# Check DNS configuration inside container docker exec <container> cat /etc/resolv.conf

# Output should show: # nameserver 127.0.0.11 # options ndots:0

# Test Docker DNS docker exec <container> nslookup other-container # Should resolve to container IP

# Test external DNS docker exec <container> nslookup google.com # Should resolve via upstream DNS ```

Fix DNS issues:

```bash # Option 1: Specify custom DNS servers for container docker run --dns 8.8.8.8 --dns 1.1.1.1 <image>

# Option 2: Configure Docker daemon DNS # /etc/docker/daemon.json { "dns": ["8.8.8.8", "1.1.1.1"], "dns-search": ["example.com"] }

# Restart Docker after daemon.json change systemctl restart docker

# Option 3: Use host DNS (bypass Docker DNS) docker run --dns-search . <image>

# Option 4: Add hosts file entries docker run --add-host=host.docker.internal:host-gateway <image> # Creates /etc/hosts entry: <host-gateway-IP> host.docker.internal

# Debug DNS issues docker run --rm busybox nslookup google.com # If this fails, check: # 1. Host DNS working? cat /etc/resolv.conf # 2. Docker daemon DNS configured? # 3. Firewall blocking DNS (port 53)? ```

DNS in Docker Compose:

```yaml # docker-compose.yml DNS configuration version: '3.8' services: web: image: nginx dns: - 8.8.8.8 - 1.1.1.1 dns_search: - example.com extra_hosts: - "api.internal:host-gateway" - "db.internal:10.0.0.50"

api: image: my-api # Can reach web by service name # http://web:80 ```

### 3. Fix container-to-container communication

Same network communication:

```bash # Containers must be on same network to communicate

# Create network docker network create mynet

# Run containers on same network docker run -d --name web --network mynet nginx docker run -d --name api --network mynet my-api

# They can now reach each other by name: # api can reach http://web:80 # web can reach http://api:8080

# Connect existing container to network docker network connect mynet <container>

# Disconnect from network docker network disconnect mynet <container>

# Container on multiple networks docker network connect frontend mynet docker network connect backend mynet # Container now on both networks ```

Different network isolation:

```bash # Containers on different networks CANNOT communicate by default

docker network create frontend docker network create backend

docker run -d --name web --network frontend nginx docker run -d --name db --network backend postgres

# web cannot reach db (isolated networks)

# Solution 1: Put both on same network docker network connect backend web # Now web is on both frontend and backend

# Solution 2: Use a proxy/gateway container on both networks docker run -d --name proxy \ --network frontend \ --network backend \ nginx

# proxy can route traffic between networks ```

Legacy links (deprecated but still works):

```bash # Old-style links (pre-docker network) docker run -d --name db postgres docker run -d --name web --link db:database nginx

# Creates: # - Environment variables: DB_PORT, DB_ENV_POSTGRES_USER, etc. # - /etc/hosts entry for 'database' # - Network connectivity

# Modern equivalent: docker network create mynet docker run -d --name db --network mynet postgres docker run -d --name web --network mynet nginx # web can reach db at http://db:5432 ```

### 4. Fix port publishing issues

Basic port publishing:

```bash # Publish port to all interfaces docker run -d -p 8080:80 nginx # Host port 8080 -> Container port 80 # Accessible at http://<host-ip>:8080

# Publish to specific interface docker run -d -p 127.0.0.1:8080:80 nginx # Only accessible from localhost

# Publish to specific IP (multi-IP hosts) docker run -d -p 192.168.1.100:8080:80 nginx

# Publish specific port range docker run -d -p 8080-8090:80-90 nginx

# UDP ports docker run -d -p 53:53/udp dns-server

# Multiple ports docker run -d -p 80:80 -p 443:443 nginx ```

Debug port publishing:

```bash # Check if port is listening ss -tlnp | grep 8080 netstat -tlnp | grep 8080

# Should show: # LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("docker-proxy",pid=1234,fd=4))

# If nothing listening: # 1. Container not running # 2. Port not published correctly # 3. Docker proxy not started

# Check port mapping docker port <container> # Output: 80/tcp -> 0.0.0.0:8080

# Test locally curl http://127.0.0.1:8080

# Test from external curl http://<host-ip>:8080

# If local works but external fails: # Check firewall ufw status iptables -L -n | grep 8080

# Check Docker binding docker inspect <container> --format '{{.HostConfig.PortBindings}}' ```

Port conflicts:

```bash # Error: "port is already allocated"

# Find what's using the port ss -tlnp | grep :80 lsof -i :80 fuser 80/tcp

# Solutions: # 1. Stop conflicting service systemctl stop nginx # If nginx using port 80

# 2. Use different host port docker run -d -p 8080:80 nginx # Use 8080 instead of 80

# 3. Bind to specific IP docker run -d -p 127.0.0.1:80:80 nginx # localhost only ```

Docker Compose port publishing:

```yaml # docker-compose.yml version: '3.8' services: web: image: nginx ports: - "8080:80" # All interfaces - "127.0.0.1:8443:443" # Localhost only - "8081-8090:80-90" # Port range

# Don't publish ports (internal only) db: image: postgres expose: - "5432" # Exposed to other services, not host ```

### 5. Fix bridge network issues

Default bridge network:

```bash # Default bridge (docker0) configuration # /etc/docker/daemon.json { "bip": "172.17.0.1/16", # Bridge IP and subnet "fixed-cidr": "172.17.0.0/16", # Container IP range "mtu": 1500 # MTU setting }

# Check current bridge ip addr show docker0

# Recreate Docker bridge # Stop Docker systemctl stop docker

# Remove existing bridge ip link set dev docker0 down ip link del docker0

# Start Docker (recreates bridge) systemctl start docker

# Verify ip addr show docker0 ```

Custom bridge network:

```bash # Create custom bridge network docker network create \ --driver bridge \ --subnet 172.20.0.0/16 \ --gateway 172.20.0.1 \ --ip-range 172.20.0.0/24 \ mynet

# Subnet options explained: # --subnet: Network address range # --gateway: Bridge IP (container default route) # --ip-range: Subset for container assignment

# Run container on custom network docker run -d --name web --network mynet nginx docker run -d --name api --network mynet my-api

# Containers get IPs from 172.20.0.0/24 range ```

Bridge network isolation:

```bash # By default, containers on default bridge can communicate by IP only # Custom bridge networks enable DNS-based service discovery

# Default bridge limitation: docker run -d --name web1 nginx docker run -d --name web2 nginx docker exec web1 ping web2 # FAILS - no DNS resolution docker exec web1 ping 172.17.0.3 # WORKS - direct IP

# Custom bridge enables name resolution: docker network create mynet docker run -d --name web1 --network mynet nginx docker run -d --name web2 --network mynet nginx docker exec web1 ping web2 # WORKS - Docker DNS ```

### 6. Fix overlay network issues (Swarm)

Overlay network requirements:

```bash # Overlay networks require Docker Swarm mode # Initialize Swarm docker swarm init --advertise-addr <manager-ip>

# Or join as worker docker swarm join --token <token> <manager-ip>:2377

# Create overlay network docker network create \ --driver overlay \ --attachable \ my-overlay

# --attachable allows standalone containers to join

# Run services on overlay docker service create \ --name web \ --network my-overlay \ --replicas 3 \ nginx

docker service create \ --name api \ --network my-overlay \ my-api

# Services can reach each other by name # Service discovery via DNS round-robin ```

Overlay encryption:

```bash # Overlay networks support encryption docker network create \ --driver overlay \ --opt encrypted \ secure-overlay

# All Swarm nodes must support encryption # Check encryption status docker network inspect secure-overlay

# If encryption not working: # 1. Ensure all nodes on same Docker version # 2. Check firewall allows IPsec (ESP protocol) # 3. Verify swarm CA certificates valid ```

Debug overlay networks:

```bash # Check overlay network status docker network ls --filter driver=overlay

# Inspect overlay docker network inspect my-overlay

# Shows: # - Subnet configuration # - Connected nodes # - Service endpoints

# Check overlay connectivity between nodes docker run --rm --network my-overlay alpine ping -c 3 api

# From specific node docker node ps --filter name=api

# Check service DNS docker exec <container> nslookup api # Should return multiple IPs (one per replica)

# Overlay not working? Check: # 1. Swarm mode active: docker info | grep -i swarm # 2. Nodes can communicate on port 4789 (VXLAN) # 3. Firewall allows overlay traffic ```

### 7. Fix firewall and iptables issues

Docker and iptables:

```bash # Docker manages iptables for NAT and forwarding # Check Docker chains iptables -L -n | grep DOCKER

# Typical Docker chains: # DOCKER - Per-container rules # DOCKER-USER - User-defined rules (persist through restarts) # DOCKER-INGRESS - Swarm ingress

# If iptables rules missing, restart Docker systemctl restart docker

# Check NAT rules iptables -t nat -L -n | grep -E "MASQUERADE|DNAT" ```

DOCKER-USER chain:

```bash # Use DOCKER-USER for custom rules that persist

# Allow specific traffic iptables -I DOCKER-USER -i eth0 -o docker0 -p tcp --dport 80 -j ACCEPT

# Block container access to specific network iptables -I DOCKER-USER -i docker0 -d 10.0.0.0/8 -j DROP

# Allow established connections iptables -I DOCKER-USER -m state --state ESTABLISHED,RELATED -j ACCEPT

# List DOCKER-USER rules iptables -L DOCKER-USER -n -v

# Flush DOCKER-USER (use carefully!) iptables -F DOCKER-USER ```

UFW (Uncomplicated Firewall) and Docker:

```bash # UFW can block Docker traffic

# Check UFW status ufw status

# If active, Docker traffic may be blocked

# Solution 1: Allow Docker traffic through UFW ufw allow from 172.17.0.0/16 to any ufw allow 2375/tcp # Docker API (if exposed) ufw allow 2376/tcp # Docker API TLS

# Solution 2: Configure UFW to not interfere with Docker # Edit /etc/default/ufw DEFAULT_FORWARD_POLICY="ACCEPT"

# Reload UFW ufw reload

# Solution 3: Disable UFW temporarily (not recommended for production) ufw disable ```

### 8. Monitor Docker networking

Network monitoring:

```bash # Watch network traffic watch -n 1 'docker network ls'

# Monitor container connections watch -n 1 'docker network inspect bridge --format "{{range .Containers}}{{.Name}} {{end}}"'

# Check network statistics docker stats

# Packet capture inside container docker run --rm --cap-add NET_RAW alpine ping -c 3 google.com

# Or tcpdump in container docker exec <container> tcpdump -i eth0 -n port 80

# Network namespace inspection nsenter --net=/var/run/docker/netns/<container-id> ip addr ```

Prometheus metrics:

```yaml # Docker daemon exposes network metrics # Enable in /etc/docker/daemon.json { "metrics-addr": "0.0.0.0:9323" }

# Scrape with Prometheus scrape_configs: - job_name: 'docker' static_configs: - targets: ['localhost:9323']

# Key metrics: # engine_daemon_container_actions # engine_daemon_networks_operations_total # network_transmit_bytes_total # network_receive_bytes_total ```

Prevention

  • Use custom bridge networks for service discovery
  • Document network topology for multi-container applications
  • Test DNS resolution as part of container health checks
  • Use Docker Compose or Swarm for consistent networking
  • Configure appropriate MTU for overlay networks
  • Monitor firewall rules that may affect Docker
  • Use DOCKER-USER chain for persistent custom rules
  • Implement network segmentation for security
  • Regular audit of network configurations
  • Set up alerting for network connectivity failures
  • **containerd: container not started**: Container failed to start
  • **address already in use**: Port conflict on host
  • **network not found**: Referenced network doesn't exist
  • **hostname doesn't match**: Container name resolution issue
  • **no route to host**: Network routing problem