
Docker Errors Networking
- 9 installs
- 9 repo stars
- Updated July 8, 2026
- openaec-foundation/docker-claude-skill-package
Helps with devops & ci/cd tasks.
About
docker-errors-networking is a Claude Code skill for devops & ci/cd. It helps solo builders move faster with AI-assisted development.
- docker-errors-networking
- DevOps & CI/CD
- AI-coding skill
Docker Errors Networking by the numbers
- 9 all-time installs (skills.sh)
- +1 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #1,020 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/docker-claude-skill-package --skill docker-errors-networkingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 9 |
|---|---|
| repo stars | ★ 9 |
| Last updated | July 8, 2026 |
| Repository | openaec-foundation/docker-claude-skill-package ↗ |
What it does
Helps with devops & ci/cd tasks.
Files
docker-errors-networking
Quick Reference
Rule #1: ALWAYS Use User-Defined Networks
NEVER use the default bridge network. It lacks DNS resolution, proper isolation, and configuration flexibility. ALWAYS create a user-defined bridge network:
docker network create mynet
docker run --network mynet --name web nginx
docker run --network mynet --name api node
# api can reach web via hostname "web" — automatic DNSNetwork Debugging Flowchart
Container cannot communicate
|
v
[Are containers on the SAME network?]
| |
NO YES
| |
v v
docker network [Can they ping by IP?]
connect mynet | |
container NO YES
| | |
v v v
Retry [Check firewall/ [DNS issue — check
iptables] container name and
See §Firewall /etc/resolv.conf]
See §DNS
|
v
[Can container reach internet?]
| |
NO YES
| |
v v
Check ip_forward Port mapping issue
and DNS config See §Port Mapping
See §No Internet---
Diagnostic Table: Symptom > Cause > Fix
DNS Resolution Failures
| Symptom | Cause | Fix |
|---|---|---|
dial tcp: lookup <hostname>: no such host | Containers on default bridge (no DNS) | ALWAYS use user-defined network: docker network create mynet |
dial tcp: lookup <hostname>: no such host on custom network | Target container name misspelled or not running | Verify: docker ps --filter network=mynet. Use exact container name or network alias |
| DNS works by container name but not by service name | Using docker run instead of Compose | Use --network-alias for custom aliases: docker run --network mynet --network-alias db postgres |
Could not resolve host for external domains | Container DNS misconfigured | Check: docker exec <ctr> cat /etc/resolv.conf. Fix: docker run --dns 8.8.8.8 or set in daemon.json |
WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf | Host uses loopback DNS (systemd-resolved/dnsmasq) | Set DNS in /etc/docker/daemon.json: {"dns": ["8.8.8.8", "8.8.4.4"]} and restart Docker |
Connection Refused
| Symptom | Cause | Fix |
|---|---|---|
connection refused between containers on same network | Target service not listening on 0.0.0.0 | NEVER bind to 127.0.0.1 inside container. ALWAYS bind to 0.0.0.0 |
connection refused from host to container | Port not published or wrong port | Verify: docker port <ctr>. Publish: docker run -p 8080:80 |
connection refused — service starting slowly | Container healthy but service not ready | Add health check with --health-cmd. Use depends_on with condition: service_healthy in Compose |
connection refused after container restart | IP address changed | NEVER hardcode container IPs. ALWAYS use container names or network aliases for DNS |
Port Mapping Issues
| Symptom | Cause | Fix |
|---|---|---|
port is already allocated / bind: address already in use | Host port in use by another process | Find: lsof -i :PORT or `ss -tlnp \ |
| Published port not accessible from outside host | Binding to localhost only | Change -p 127.0.0.1:8080:80 to -p 8080:80 to bind all interfaces |
| Port published but no response | Container process crashed or not listening | Check: docker logs <ctr> and docker exec <ctr> ss -tlnp |
-P maps to unexpected ports | EXPOSE in Dockerfile not matching actual service port | ALWAYS use explicit -p host:container instead of -P in production |
Default Bridge Limitations
| Symptom | Cause | Fix |
|---|---|---|
| Containers cannot reach each other by name | Default bridge lacks embedded DNS | Migrate to user-defined bridge: docker network create mynet |
| All containers see each other (no isolation) | Default bridge connects all unspecified containers | Use separate user-defined networks per application stack |
| Cannot connect/disconnect without restart | Default bridge does not support live operations | User-defined bridges support: docker network connect/disconnect |
No Internet from Container
| Symptom | Cause | Fix |
|---|---|---|
ping: bad address or no route to host | IP forwarding disabled on host | Enable: sysctl -w net.ipv4.ip_forward=1. Persist in /etc/sysctl.conf |
| DNS works but HTTP times out | Firewall blocking outbound traffic | Check iptables FORWARD chain. Docker needs ACCEPT for its bridge subnets |
--network host works but bridge does not | NAT/masquerade not working | Verify: iptables -t nat -L POSTROUTING. Restart Docker to rebuild rules |
| No connectivity after Docker upgrade | iptables rules lost | sudo systemctl restart docker to regenerate network rules |
Firewall and iptables Conflicts
| Symptom | Cause | Fix |
|---|---|---|
driver failed programming external connectivity | iptables conflict or stale rules | Restart Docker: sudo systemctl restart docker. Check iptables rules |
| Firewalld/ufw blocking Docker traffic | Host firewall overriding Docker iptables | For ufw: allow Docker subnet. For firewalld: add Docker zone. Or set "iptables": true in daemon.json |
docker0 bridge disappears | NetworkManager or systemd-networkd managing Docker interfaces | Mark docker0 as unmanaged in NetworkManager or systemd-networkd config |
| Containers lose connectivity after firewall reload | Firewall flush removed Docker chains | ALWAYS restart Docker after firewall changes: sudo systemctl restart docker |
Overlay Network Issues
| Symptom | Cause | Fix |
|---|---|---|
| Cannot create overlay network | Swarm mode not initialized | Initialize: docker swarm init or join an existing swarm |
| Standalone containers cannot join overlay | Network not attachable | Create with --attachable: docker network create -d overlay --attachable mynet |
| Cross-host communication fails | Required ports blocked between hosts | Open: 2377/tcp (control), 4789/udp (VXLAN), 7946/tcp+udp (node discovery) |
| Encrypted overlay fails on Windows | Windows limitation | Encrypted overlay is NOT supported on Windows. Use unencrypted or different approach |
Subnet Conflicts
| Symptom | Cause | Fix |
|---|---|---|
| Containers cannot reach host network resources | Docker subnet overlaps with host/VPN network | Specify non-conflicting subnet: docker network create --subnet=10.99.0.0/16 mynet |
| VPN breaks after Docker install | Docker default pools conflict with VPN ranges | Configure in /etc/docker/daemon.json: {"default-address-pools": [{"base": "10.99.0.0/16", "size": 24}]} |
network X has active endpoints when removing | Containers still connected | Disconnect all: docker network disconnect -f mynet <ctr> then remove |
---
Network Debugging Commands
Essential Diagnostic Commands
# Check which network a container is on
docker inspect --format='{{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{end}}' <ctr>
# Get container IP address
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <ctr>
# List all containers on a network
docker network inspect --format='{{range .Containers}}{{.Name}} {{end}}' mynet
# Check DNS resolution inside container
docker exec <ctr> nslookup <target-hostname>
docker exec <ctr> cat /etc/resolv.conf
# Test connectivity between containers
docker exec <ctr> ping -c 2 <target-hostname>
docker exec <ctr> wget -qO- http://<target-hostname>:<port>/
# Check listening ports inside container
docker exec <ctr> ss -tlnp
docker exec <ctr> netstat -tlnp
# Check published port mapping
docker port <ctr>
# Inspect full network configuration
docker network inspect mynet
# Check iptables rules (host)
sudo iptables -L -n -v
sudo iptables -t nat -L -n -v
# Check IP forwarding (host)
sysctl net.ipv4.ip_forwardCompose-Specific Debugging
# Check default network created by Compose
docker network ls --filter "label=com.docker.compose.project=<project>"
# Verify service DNS names
docker compose exec <service> nslookup <other-service>
# Check Compose network config
docker compose config | grep -A 10 networks---
Compose Networking Patterns
Correct: Services on Shared Network
# docker-compose.yml
services:
web:
image: nginx
ports:
- "8080:80" # Only needed for external access
networks:
- app-net
api:
image: node:20-alpine
networks:
- app-net # Can reach "web" by hostname
networks:
app-net:
driver: bridgeCorrect: Isolated Backend Network
services:
web:
networks:
- frontend
- backend
api:
networks:
- backend
db:
networks:
- backend # Not accessible from frontend
networks:
frontend:
backend:
internal: true # No external internet accessAnti-Pattern: Missing Network Declaration
# NEVER rely on the default Compose network for multi-project setups
# ALWAYS declare explicit networks when services need cross-project communication
services:
api:
networks:
- shared-net
networks:
shared-net:
external: true # Must exist before compose up---
Critical Rules
ALWAYS use user-defined bridge networks -- the default bridge lacks DNS, isolation, and live connect/disconnect.
ALWAYS bind services to 0.0.0.0 inside containers -- binding to 127.0.0.1 makes the service unreachable from other containers.
ALWAYS restart Docker after firewall changes -- firewall reloads flush Docker's iptables chains.
NEVER hardcode container IP addresses -- IPs change on restart. Use DNS names or network aliases.
NEVER use --link -- it is legacy and deprecated. Use user-defined networks with DNS.
NEVER expose ports with -p for container-to-container communication -- containers on the same network can reach all ports directly.
---
Reference Links
- references/diagnostics.md -- Complete error-to-cause-to-solution lookup table
- references/examples.md -- Network debugging sessions with step-by-step resolution
- references/anti-patterns.md -- Networking configuration mistakes and why they fail
Official Sources
- https://docs.docker.com/engine/network/
- https://docs.docker.com/engine/network/drivers/bridge/
- https://docs.docker.com/engine/network/drivers/overlay/
- https://docs.docker.com/engine/daemon/troubleshoot/
Networking Anti-Patterns — What NOT to Do
Common Docker networking configuration mistakes, why they fail, and the correct alternative.
Docker Engine 24+, Docker Compose v2.
---
AP-001: Using the Default Bridge Network
The Mistake
# Relying on the default bridge for container communication
docker run -d --name redis redis
docker run -d --name webapp myapp
# webapp tries to connect to "redis" by hostname — FAILSWhy It Fails
The default bridge network does NOT provide embedded DNS resolution. Containers can only reach each other by IP address, which changes on restart. The legacy --link flag provides name resolution but is deprecated and not maintained.
The Correct Way
# ALWAYS create and use a user-defined bridge network
docker network create app-net
docker run -d --name redis --network app-net redis
docker run -d --name webapp --network app-net myapp
# webapp can now reach "redis" by hostname via Docker's embedded DNS---
AP-002: Hardcoding Container IP Addresses
The Mistake
# Application config
DATABASE_HOST = "172.18.0.3" # Hardcoded container IP
REDIS_HOST = "172.18.0.4"Why It Fails
Container IP addresses are assigned dynamically and change every time a container is recreated, restarted, or moved to a different network. Hardcoded IPs break silently when infrastructure changes.
The Correct Way
# ALWAYS use container names or network aliases
DATABASE_HOST = "db" # Docker DNS resolves this
REDIS_HOST = "redis" # Docker DNS resolves this# Or use network aliases for more descriptive names
docker run --network app-net --network-alias database postgres---
AP-003: Binding Services to 127.0.0.1 Inside Containers
The Mistake
// Node.js server inside container
app.listen(3000, '127.0.0.1'); // Only accessible from inside this container# Flask inside container
app.run(host='127.0.0.1', port=5000) # Only accessible from inside this containerWhy It Fails
127.0.0.1 (localhost) inside a container refers to the container's own loopback interface. Other containers — even on the same Docker network — cannot reach this address. It is container-private.
The Correct Way
// ALWAYS bind to 0.0.0.0 inside containers
app.listen(3000, '0.0.0.0'); // Accessible from all network interfaces# ALWAYS bind to 0.0.0.0 inside containers
app.run(host='0.0.0.0', port=5000)---
AP-004: Using --link for Container Communication
The Mistake
docker run -d --name redis redis
docker run -d --name webapp --link redis:redis myappWhy It Fails
--link is legacy and deprecated. It only works on the default bridge, does not support user-defined networks, cannot be updated without container recreation, and creates fragile coupling between containers.
The Correct Way
docker network create app-net
docker run -d --name redis --network app-net redis
docker run -d --name webapp --network app-net myapp
# DNS-based discovery — no --link needed---
AP-005: Publishing Ports for Container-to-Container Communication
The Mistake
# docker-compose.yml
services:
api:
image: myapi
ports:
- "3000:3000" # Published to host — unnecessary for inter-service traffic
web:
image: myweb
environment:
API_URL: "http://localhost:3000" # Tries to reach via host — fragileWhy It Fails
Port publishing (-p / ports:) maps a container port to a host port. This is only needed for access from outside the Docker network. Containers on the same network can reach ALL ports of other containers directly — no publishing needed. Using localhost from one container does NOT reach another container.
The Correct Way
services:
api:
image: myapi
# NO ports: needed for inter-service communication
# Only add ports: if external access is required
web:
image: myweb
ports:
- "8080:80" # Only web needs external access
environment:
API_URL: "http://api:3000" # Use service name, not localhost---
AP-006: Using depends_on Without Health Checks
The Mistake
services:
db:
image: postgres:16
# No healthcheck defined
webapp:
depends_on:
- db # Only waits for container START, not service READYWhy It Fails
depends_on without condition: service_healthy only ensures the database container has started. PostgreSQL may take several seconds to initialize. The webapp connects immediately and gets connection refused because the database is not accepting connections yet.
The Correct Way
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
webapp:
depends_on:
db:
condition: service_healthy # Waits for health check to pass---
AP-007: Ignoring Network Isolation Between Compose Projects
The Mistake
# Project A
cd frontend && docker compose up -d
# Project B
cd backend && docker compose up -d
# Expecting frontend to reach backend by service name — FAILSWhy It Fails
Each Compose project creates its own isolated default network (frontend_default, backend_default). Services in different projects cannot see each other because they are on separate networks with separate DNS scopes.
The Correct Way
# Create shared network first
docker network create shared-services# Both projects reference the external network
networks:
shared:
external: true
name: shared-services
services:
myservice:
networks:
- default # Keep internal communication
- shared # Add cross-project access---
AP-008: Not Configuring Docker Address Pools with VPN
The Mistake
# Install Docker with default settings on a machine with corporate VPN
# Docker creates networks in 172.17-28.x.x and 192.168.x.x ranges
# VPN routes to 172.16.0.0/12 stop workingWhy It Fails
Docker's default address pools (172.17.0.0/16 through 172.28.0.0/14, 192.168.0.0/16) overlap with many corporate VPN ranges. Docker's local routes take precedence, breaking VPN connectivity to those subnets.
The Correct Way
// /etc/docker/daemon.json — configure BEFORE creating any networks
{
"default-address-pools": [
{
"base": "10.99.0.0/16",
"size": 24
}
]
}sudo systemctl restart docker
# All new networks will use 10.99.x.x — no VPN conflict---
AP-009: Forgetting to Restart Docker After Firewall Changes
The Mistake
# Reload firewall rules
sudo firewall-cmd --reload
# or: sudo ufw reload
# or: sudo iptables -F
# All Docker containers lose network connectivity
# Admin does not restart DockerWhy It Fails
Docker creates iptables chains (DOCKER, DOCKER-ISOLATION, DOCKER-USER) and NAT MASQUERADE rules at startup. When the firewall flushes iptables, these chains are destroyed. Without them, Docker cannot route traffic between containers or to the internet.
The Correct Way
# ALWAYS restart Docker after any firewall change
sudo firewall-cmd --reload && sudo systemctl restart docker
# Or automate with systemd:
# /etc/systemd/system/firewalld.service.d/docker.conf
[Service]
ExecStartPost=/usr/bin/systemctl restart docker---
AP-010: Using host.docker.internal in Production
The Mistake
services:
webapp:
environment:
DB_HOST: "host.docker.internal" # Relies on Docker Desktop featureWhy It Fails
host.docker.internal is a Docker Desktop convenience feature. It does NOT work reliably on Linux Docker Engine in production. It is not a standard DNS name and its behavior varies across platforms and Docker versions.
The Correct Way
# For container-to-container: use Docker service names
services:
webapp:
environment:
DB_HOST: "db" # Another container on the same network
# For container-to-host on Linux:
# Use the host gateway IP or --network host
services:
webapp:
extra_hosts:
- "host.docker.internal:host-gateway" # Explicit and portable---
AP-011: Exposing Database Ports to the Host
The Mistake
services:
db:
image: postgres:16
ports:
- "5432:5432" # Database accessible from entire networkWhy It Fails
Publishing the database port to the host makes it accessible from any machine that can reach the host. This is a security risk — databases should only be accessible from application containers, not from the network.
The Correct Way
services:
db:
image: postgres:16
# NO ports: — only accessible from containers on the same network
networks:
- backend
webapp:
image: myapp
networks:
- backend
environment:
DB_HOST: db # Reaches database via internal network
networks:
backend:
internal: true # Optional: also blocks internet access from db# If you need temporary host access for debugging:
# Use a one-off port-forward instead of permanent publishing
docker exec -it db psql -U postgres---
AP-012: Not Using internal Networks for Backend Services
The Mistake
services:
web:
networks:
- app-net
db:
networks:
- app-net # Database has full internet access — unnecessary riskWhy It Fails
By default, all Docker bridge networks allow outbound internet access. A compromised database container could exfiltrate data or download malware. Backend services (databases, caches, message queues) rarely need internet access.
The Correct Way
services:
web:
networks:
- frontend
- backend
db:
networks:
- backend # Cannot reach internet
networks:
frontend:
# Normal network — internet access allowed
backend:
internal: true # No outbound internet — maximum isolation---
Summary Table
| # | Anti-Pattern | Risk | Correct Approach |
|---|---|---|---|
| AP-001 | Default bridge network | No DNS, no isolation | User-defined bridge networks |
| AP-002 | Hardcoded container IPs | Breaks on restart | DNS names or network aliases |
| AP-003 | Bind to 127.0.0.1 in container | Unreachable from other containers | Bind to 0.0.0.0 |
| AP-004 | --link flag | Deprecated, fragile | User-defined networks |
| AP-005 | Publish ports for inter-container traffic | Unnecessary host exposure | Direct container-to-container on same network |
| AP-006 | depends_on without health check | Race condition on startup | condition: service_healthy |
| AP-007 | Assume cross-project DNS works | Projects are network-isolated | Shared external network |
| AP-008 | Default address pools with VPN | VPN routes broken | Custom address pools in daemon.json |
| AP-009 | Skip Docker restart after firewall change | All containers lose network | ALWAYS restart Docker after firewall changes |
| AP-010 | host.docker.internal in production | Platform-dependent, unreliable | Service names or explicit host mapping |
| AP-011 | Publish database ports | Security exposure | Internal network, no port publishing |
| AP-012 | Internet access for backend services | Data exfiltration risk | internal: true networks |
Network Error Diagnostics — Complete Reference
Full error-to-cause-to-solution lookup table for Docker networking issues.
Docker Engine 24+, Docker Compose v2.
---
DNS Resolution Errors
| # | Error / Symptom | Root Cause | Solution | Verify Fix |
|---|---|---|---|---|
| N-001 | dial tcp: lookup <hostname>: no such host | Containers on default bridge network (no embedded DNS) | ALWAYS use user-defined network: docker network create mynet && docker run --network mynet | docker exec <ctr> nslookup <target> returns IP |
| N-002 | dial tcp: lookup <hostname>: no such host on user-defined network | Target container not running or name misspelled | Check: docker ps --filter network=mynet. Verify exact container name matches lookup target | docker network inspect mynet shows both containers |
| N-003 | DNS resolves but wrong IP returned | Stale DNS cache or container recreated with new IP | Restart client container. NEVER cache IPs — Docker DNS handles resolution | docker exec <ctr> nslookup <target> shows correct IP |
| N-004 | Could not resolve host: github.com | Container cannot reach external DNS | Check docker exec <ctr> cat /etc/resolv.conf. Set DNS: docker run --dns 8.8.8.8 | docker exec <ctr> nslookup github.com succeeds |
| N-005 | WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf | Host uses loopback DNS resolver (systemd-resolved, dnsmasq) | Set in /etc/docker/daemon.json: {"dns": ["8.8.8.8", "8.8.4.4"]}. Restart Docker | Warning disappears from docker run output |
| N-006 | DNS works with --network host but not bridge | Docker DNS server (127.0.0.11) not reachable | Check iptables NAT rules. Restart Docker to regenerate: sudo systemctl restart docker | docker exec <ctr> cat /etc/resolv.conf shows 127.0.0.11 |
| N-007 | Service name resolution fails in docker run | docker run does not support Compose service names | Use --network-alias: docker run --network mynet --network-alias db postgres | docker exec <client> nslookup db resolves |
| N-008 | DNS resolution intermittently fails | Docker embedded DNS overwhelmed or host DNS flaky | Add fallback DNS: docker run --dns 8.8.8.8 --dns 1.1.1.1. Check host DNS stability | Monitor with repeated nslookup from inside container |
---
Connection Refused Errors
| # | Error / Symptom | Root Cause | Solution | Verify Fix |
|---|---|---|---|---|
| N-010 | connection refused between containers on same network | Service binding to 127.0.0.1 instead of 0.0.0.0 | Configure service to listen on 0.0.0.0. Example: node --host 0.0.0.0 | docker exec <target> ss -tlnp shows 0.0.0.0:<port> |
| N-011 | connection refused from host to published port | Service not started yet or crashed | Check: docker logs <ctr>. Verify service health: docker inspect --format='{{.State.Health.Status}}' <ctr> | curl localhost:<host-port> succeeds |
| N-012 | connection refused after container restart | Client caching old IP address | NEVER hardcode IPs. ALWAYS use DNS names. Restart client if it cached the IP | Connection succeeds using hostname |
| N-013 | connection refused — health check passes but app unreachable | Health check URL differs from application endpoint | Verify health check tests the actual service port. Check: docker inspect --format='{{json .State.Health}}' <ctr> | Application responds on expected port |
| N-014 | connection refused to database on startup | Database not ready when app starts | Use depends_on with condition: service_healthy in Compose. Add retry logic in application | App connects after DB health check passes |
| N-015 | connection refused between containers on DIFFERENT networks | Networks are isolated by design | Connect containers to a shared network: docker network connect shared-net <ctr> | Both containers visible in docker network inspect shared-net |
---
Port Mapping Errors
| # | Error / Symptom | Root Cause | Solution | Verify Fix |
|---|---|---|---|---|
| N-020 | port is already allocated | Another process (or container) already bound to that host port | Find: lsof -i :<port> or `ss -tlnp \ | grep <port>`. Stop conflicting process or choose different port |
| N-021 | bind: address already in use | Same as N-020 — different OS error message | Same as N-020 | Same as N-020 |
| N-022 | Published port not reachable from other machines | Port bound to localhost only (-p 127.0.0.1:8080:80) | Remove IP binding: -p 8080:80 binds to all interfaces | curl <host-ip>:8080 from remote machine succeeds |
| N-023 | -P maps to random high ports | -P publishes all EXPOSE ports to random host ports | ALWAYS use explicit -p host:container in production. Use docker port <ctr> to find mappings | docker port <ctr> shows expected mapping |
| N-024 | Port mapping exists but no response | Container process not listening on the container port | Check: docker exec <ctr> ss -tlnp. Verify EXPOSE matches actual service port | ss -tlnp output shows service on expected port |
| N-025 | UDP port not working | Default protocol is TCP | Specify UDP: -p 5060:5060/udp or both: -p 5060:5060/tcp -p 5060:5060/udp | docker port <ctr> shows UDP mapping |
| N-026 | Port range mapping fails | Ranges must match in size | Ensure equal ranges: -p 8000-8010:8000-8010 (same count of ports) | docker port <ctr> lists all range mappings |
---
Firewall and iptables Errors
| # | Error / Symptom | Root Cause | Solution | Verify Fix |
|---|---|---|---|---|
| N-030 | driver failed programming external connectivity on endpoint | iptables rules corrupted or conflicting | Restart Docker: sudo systemctl restart docker | Container starts with port mapping |
| N-031 | Containers lose network after firewall-cmd --reload or ufw reload | Firewall flush removes Docker iptables chains | ALWAYS restart Docker after firewall changes: sudo systemctl restart docker | iptables -L DOCKER shows rules |
| N-032 | ufw blocking container traffic despite allowing port | ufw FORWARD chain drops Docker traffic | Add ufw rule for Docker subnet or edit /etc/ufw/after.rules to allow Docker bridge | Container traffic flows through firewall |
| N-033 | firewalld blocking Docker traffic | Docker zone not configured in firewalld | Add Docker interface to trusted zone: firewall-cmd --zone=trusted --add-interface=docker0 --permanent | firewall-cmd --get-active-zones shows docker0 |
| N-034 | docker0 bridge interface disappears | NetworkManager or systemd-networkd managing Docker interfaces | Mark unmanaged. For NM: [keyfile]\nunmanaged-devices=interface-name:docker* in /etc/NetworkManager/conf.d/ | ip link show docker0 exists after restart |
| N-035 | Container-to-container blocked despite same network | ICC (inter-container connectivity) disabled | Check bridge option: docker network inspect mynet. Create with ICC enabled (default) | Containers can ping each other |
---
Internet Connectivity Errors
| # | Error / Symptom | Root Cause | Solution | Verify Fix |
|---|---|---|---|---|
| N-040 | Container cannot reach any external IP | IP forwarding disabled on host | Enable: sysctl -w net.ipv4.ip_forward=1. Persist: add net.ipv4.ip_forward=1 to /etc/sysctl.conf | docker exec <ctr> ping -c 1 8.8.8.8 succeeds |
| N-041 | DNS resolves but HTTP/HTTPS times out | Firewall blocking outbound traffic on FORWARD chain | Check: iptables -L FORWARD -n -v. Allow Docker subnet outbound traffic | docker exec <ctr> wget -qO- http://example.com succeeds |
| N-042 | --network host has internet but bridge does not | NAT/masquerade rules missing | Restart Docker to rebuild: sudo systemctl restart docker. Check iptables -t nat -L POSTROUTING | MASQUERADE rule exists for Docker subnet |
| N-043 | Internet works for some containers, not others | Container on --internal network | Check: docker network inspect <net>. Internal networks block all external traffic by design | Move container to non-internal network |
| N-044 | No connectivity after Docker/system upgrade | iptables rules not regenerated | sudo systemctl restart docker | iptables -L DOCKER -n shows populated chain |
| N-045 | Proxy-related connection failures | Container needs HTTP_PROXY set | Set via env: docker run -e HTTP_PROXY=http://proxy:3128 -e HTTPS_PROXY=http://proxy:3128 | docker exec <ctr> wget http://example.com through proxy |
---
Overlay Network Errors
| # | Error / Symptom | Root Cause | Solution | Verify Fix |
|---|---|---|---|---|
| N-050 | network mynet not found for overlay | Swarm mode not initialized | docker swarm init on manager node | docker network create -d overlay mynet succeeds |
| N-051 | Standalone container cannot join overlay | Network not created as attachable | Recreate: docker network create -d overlay --attachable mynet | docker run --network mynet works for standalone containers |
| N-052 | Cross-host overlay communication fails | Swarm ports blocked between hosts | Open: 2377/tcp, 4789/udp, 7946/tcp+udp between all Swarm nodes | docker node ls shows all nodes as Ready |
| N-053 | Overlay encryption fails on Windows | Windows does not support IPsec on overlay | Remove --opt encrypted. Use application-level TLS instead | Overlay works without encryption flag |
| N-054 | Overlay network performance degraded | VXLAN overhead + encryption overhead | Benchmark with/without encryption. Consider host networking for latency-critical services | iperf3 shows acceptable throughput |
---
Subnet Conflict Errors
| # | Error / Symptom | Root Cause | Solution | Verify Fix |
|---|---|---|---|---|
| N-060 | VPN connection breaks after Docker starts | Docker default subnet (172.17.0.0/16) overlaps VPN range | Set custom pools in /etc/docker/daemon.json: {"default-address-pools": [{"base": "10.99.0.0/16", "size": 24}]} | VPN and Docker work simultaneously |
| N-061 | Cannot reach specific host network IPs | Docker network overlaps with host LAN subnet | Create network with non-conflicting subnet: docker network create --subnet=10.99.0.0/16 mynet | Container can reach LAN IPs |
| N-062 | network X has active endpoints when removing network | Containers still connected to network | Disconnect all: docker network disconnect -f mynet <ctr> for each container, then remove | docker network rm mynet succeeds |
| N-063 | Pool overlaps with other one on this address space | Another Docker network already uses requested subnet | Choose different subnet or remove conflicting network: docker network ls to find it | New network creates with desired subnet |
| N-064 | All Docker default subnets exhausted | Too many networks created consuming all default pool space | Increase pool or use larger subnets. Clean unused: docker network prune | New networks create successfully |
---
Docker Compose Networking Errors
| # | Error / Symptom | Root Cause | Solution | Verify Fix |
|---|---|---|---|---|
| N-070 | Service A cannot reach Service B by name | Services on different explicitly declared networks | Ensure both services list the same network in their networks: key | docker compose exec A nslookup B resolves |
| N-071 | network X declared as external, but could not be found | External network does not exist yet | Create first: docker network create X before docker compose up | docker compose up succeeds |
| N-072 | Port conflict between Compose projects | Two projects mapping same host port | Use different host ports per project or use host_ip to bind to different interfaces | Both projects start without port conflict |
| N-073 | Container names conflict across Compose projects | Custom container_name collides | Remove container_name — let Compose auto-generate unique names. Or use distinct names | docker compose up for both projects succeeds |
| N-074 | Cross-project service communication fails | Each Compose project creates its own isolated network | Create shared external network. Declare in both compose files with external: true | Services across projects can reach each other |
| N-075 | DNS resolution uses wrong container after scale | Compose round-robins between replicas | This is expected behavior. For sticky sessions, use application-level routing | Verify with repeated nslookup showing different IPs |
---
Diagnostic Command Reference
Quick Diagnosis Checklist
# 1. Are containers on the same network?
docker inspect --format='{{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{end}}' <ctr1>
docker inspect --format='{{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{end}}' <ctr2>
# 2. Can they resolve each other?
docker exec <ctr1> nslookup <ctr2-name>
# 3. Can they ping each other?
docker exec <ctr1> ping -c 2 <ctr2-name>
# 4. Is the service listening?
docker exec <target> ss -tlnp
# 5. What does the DNS config look like?
docker exec <ctr> cat /etc/resolv.conf
# 6. What is the full network config?
docker network inspect <network-name>
# 7. What ports are published?
docker port <ctr>
# 8. Is IP forwarding on?
sysctl net.ipv4.ip_forward
# 9. Are Docker iptables chains present?
sudo iptables -L DOCKER -n -v 2>/dev/null || echo "No DOCKER chain"
# 10. Docker daemon logs
journalctl -u docker --no-pager -n 50Network Debugging Sessions — Worked Examples
Step-by-step debugging sessions showing how to diagnose and resolve Docker networking issues.
Docker Engine 24+, Docker Compose v2.
---
Session 1: Containers Cannot Communicate by Name
Scenario
Two containers started with docker run. Web app tries to connect to redis:6379 but gets dial tcp: lookup redis: no such host.
Diagnosis
# Step 1: Check what network each container is on
docker inspect --format='{{range $k, $v := .NetworkSettings.Networks}}{{$k}}{{end}}' webapp
# Output: bridge
docker inspect --format='{{range $k, $v := .NetworkSettings.Networks}}{{$k}}{{end}}' redis
# Output: bridge
# Step 2: Both on "bridge" (default) — this is the problem
# Default bridge does NOT provide DNS resolution
# Step 3: Verify DNS is broken
docker exec webapp nslookup redis
# Output: ** server can't find redis: NXDOMAINFix
# Create user-defined network
docker network create app-net
# Stop and recreate containers on the new network
docker stop webapp redis
docker rm webapp redis
docker run -d --name redis --network app-net redis:7-alpine
docker run -d --name webapp --network app-net -p 8080:8080 mywebapp
# Verify DNS works
docker exec webapp nslookup redis
# Output: Name: redis Address: 172.20.0.2
docker exec webapp ping -c 1 redis
# Output: PING redis (172.20.0.2): 56 data bytes — 64 bytes from 172.20.0.2Key Lesson
ALWAYS use user-defined networks. The default bridge is legacy and lacks DNS resolution between containers.
---
Session 2: Port Already Allocated
Scenario
Starting a container with -p 3000:3000 fails with Error: port is already allocated.
Diagnosis
# Step 1: Find what is using port 3000
# On Linux:
sudo lsof -i :3000
# Output: node 12345 user TCP *:3000 (LISTEN)
# Or:
sudo ss -tlnp | grep 3000
# Output: LISTEN 0 128 *:3000 *:* users:(("node",pid=12345,fd=19))
# Step 2: It's a local Node.js dev server using the same portFix
# Option A: Stop the conflicting process
kill 12345
# Option B: Use a different host port
docker run -d -p 3001:3000 --name myapp myimage
# Access via localhost:3001, container still listens on 3000
# Option C: Check for orphaned Docker containers
docker ps -a --filter "publish=3000"
# If found, remove: docker rm -f <container-id>Key Lesson
ALWAYS check for port conflicts before starting containers. Use lsof or ss to identify the blocking process.
---
Session 3: Service Binds to 127.0.0.1 Inside Container
Scenario
Container A can ping Container B by name, but curl http://api:8080 returns connection refused.
Diagnosis
# Step 1: Verify DNS works
docker exec web nslookup api
# Output: Name: api Address: 172.20.0.3 — DNS is fine
# Step 2: Verify ping works
docker exec web ping -c 1 api
# Output: 64 bytes from 172.20.0.3 — Network layer is fine
# Step 3: Check what the target service is listening on
docker exec api ss -tlnp
# Output: LISTEN 0 128 127.0.0.1:8080 *:* — PROBLEM FOUND
# The service binds to 127.0.0.1, only reachable from inside its own container
# Step 4: Verify from inside the target container
docker exec api curl -s http://127.0.0.1:8080
# Output: OK — works locally but not from other containersFix
# Change application config to bind to 0.0.0.0:8080
# For Node.js:
# app.listen(8080, '0.0.0.0')
# For Python Flask:
# app.run(host='0.0.0.0', port=8080)
# For Go:
# http.ListenAndServe(":8080", handler) — empty host = all interfaces
# After fix:
docker exec api ss -tlnp
# Output: LISTEN 0 128 0.0.0.0:8080 *:* — correct
docker exec web curl -s http://api:8080
# Output: OKKey Lesson
ALWAYS bind to 0.0.0.0 inside containers. Binding to 127.0.0.1 makes the service unreachable from any other container, even on the same network.
---
Session 4: Docker Breaks VPN Connectivity
Scenario
After installing Docker, VPN connections to 10.0.0.0/8 range stop working. Some corporate hosts become unreachable.
Diagnosis
# Step 1: Check Docker network subnets
docker network ls
docker network inspect bridge --format='{{range .IPAM.Config}}{{.Subnet}}{{end}}'
# Output: 172.17.0.0/16
# Step 2: Check other Docker networks
docker network inspect $(docker network ls -q) --format='{{.Name}}: {{range .IPAM.Config}}{{.Subnet}}{{end}}'
# Output:
# bridge: 172.17.0.0/16
# mynet1: 172.18.0.0/16
# mynet2: 172.19.0.0/16
# Step 3: Check routing table
ip route | grep 172
# Docker routes override VPN routes for overlapping ranges
# Step 4: Check if Docker's default pool conflicts
# Default pools: 172.17.0.0/16 through 172.28.0.0/14, 192.168.0.0/16
# If VPN uses any 172.x.x.x or 192.168.x.x — conflictFix
# Configure Docker to use non-conflicting address pools
# Edit /etc/docker/daemon.json:
{
"default-address-pools": [
{
"base": "10.99.0.0/16",
"size": 24
}
]
}
# Restart Docker
sudo systemctl restart docker
# Remove old networks and recreate
docker network prune -f
docker network create mynet
docker network inspect mynet --format='{{range .IPAM.Config}}{{.Subnet}}{{end}}'
# Output: 10.99.0.0/24 — no longer conflictsKey Lesson
ALWAYS configure custom address pools when Docker runs alongside VPNs or in environments with specific network requirements. The default pools (172.17-28.x.x, 192.168.x.x) conflict with many corporate networks.
---
Session 5: Containers Lose Network After Firewall Reload
Scenario
After running firewall-cmd --reload (or ufw reload), all Docker containers lose internet connectivity.
Diagnosis
# Step 1: Test connectivity
docker exec webapp ping -c 1 8.8.8.8
# Output: ping: sendto: Operation not permitted
# Step 2: Check Docker iptables chains
sudo iptables -L DOCKER -n
# Output: Chain DOCKER (0 references) — chain exists but no references
sudo iptables -L FORWARD -n
# Output: FORWARD chain shows DROP default, no Docker rules
# Step 3: The firewall reload flushed all iptables rules including Docker's NAT and filter chainsFix
# Restart Docker to regenerate all iptables rules
sudo systemctl restart docker
# Verify rules are back
sudo iptables -L DOCKER -n -v
# Output: Chain DOCKER with forwarding rules
sudo iptables -t nat -L POSTROUTING -n
# Output: MASQUERADE rule for Docker subnet
# Test connectivity
docker exec webapp ping -c 1 8.8.8.8
# Output: 64 bytes from 8.8.8.8Prevention
# Create a systemd override to restart Docker after firewall reload
# For firewalld:
sudo mkdir -p /etc/systemd/system/firewalld.service.d
cat <<'EOF' | sudo tee /etc/systemd/system/firewalld.service.d/docker.conf
[Service]
ExecStartPost=/usr/bin/systemctl restart docker
EOF
sudo systemctl daemon-reloadKey Lesson
ALWAYS restart Docker after any firewall changes. Firewall reloads flush iptables rules, destroying Docker's network configuration. Automate this with systemd dependencies.
---
Session 6: Compose Cross-Project Communication
Scenario
Two Compose projects need to communicate. Project A (frontend) needs to reach Project B's (backend) API service, but nslookup api fails.
Diagnosis
# Step 1: Check networks created by each project
docker network ls --filter "label=com.docker.compose.project=frontend"
# Output: frontend_default
docker network ls --filter "label=com.docker.compose.project=backend"
# Output: backend_default
# Step 2: Each project has its own isolated network — they cannot see each other
docker network inspect frontend_default --format='{{range .Containers}}{{.Name}} {{end}}'
# Output: frontend-web-1
docker network inspect backend_default --format='{{range .Containers}}{{.Name}} {{end}}'
# Output: backend-api-1 backend-db-1Fix
# Step 1: Create a shared external network
docker network create shared-services
# Step 2: Update frontend docker-compose.yml# frontend/docker-compose.yml
services:
web:
image: nginx
networks:
- default
- shared
networks:
shared:
external: true
name: shared-services# backend/docker-compose.yml
services:
api:
image: node:20-alpine
networks:
- default
- shared
db:
image: postgres:16
networks:
- default # NOT on shared network — stays isolated
networks:
shared:
external: true
name: shared-services# Step 3: Restart both projects
docker compose -f backend/docker-compose.yml up -d
docker compose -f frontend/docker-compose.yml up -d
# Step 4: Verify cross-project DNS
docker compose -f frontend/docker-compose.yml exec web nslookup api
# Output: Name: api Address: 10.99.1.3Key Lesson
Compose projects are network-isolated by default. For cross-project communication, ALWAYS create a shared external network and add only the services that need to communicate.
---
Session 7: Container Cannot Reach the Internet
Scenario
A freshly installed Docker host. Containers can ping each other but cannot reach external hosts.
Diagnosis
# Step 1: Test external connectivity
docker run --rm alpine ping -c 1 8.8.8.8
# Output: PING 8.8.8.8: sendto: Network is unreachable
# Step 2: Check IP forwarding
sysctl net.ipv4.ip_forward
# Output: net.ipv4.ip_forward = 0 — DISABLED
# Step 3: Check NAT rules
sudo iptables -t nat -L POSTROUTING -n
# Output: (empty or no MASQUERADE rule)Fix
# Step 1: Enable IP forwarding
sudo sysctl -w net.ipv4.ip_forward=1
# Step 2: Make persistent
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
# Step 3: Restart Docker to create NAT rules
sudo systemctl restart docker
# Step 4: Verify
docker run --rm alpine ping -c 1 8.8.8.8
# Output: 64 bytes from 8.8.8.8
sudo iptables -t nat -L POSTROUTING -n
# Output: MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16Key Lesson
Docker requires net.ipv4.ip_forward=1 for containers to reach the internet via NAT. ALWAYS verify this setting on fresh installations.
---
Session 8: Health Check with Networking Dependency
Scenario
Web application connects to database on startup. Compose starts both, but web crashes because database is not ready.
Diagnosis
docker compose up
# webapp exits with: connection refused to db:5432
# Database is still initializingFix
# docker-compose.yml
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
webapp:
image: mywebapp
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: "postgres://postgres:secret@db:5432/app"docker compose up -d
# webapp waits until db health check passes before starting
# Verify health
docker compose ps
# NAME STATUS
# db running (healthy)
# webapp runningKey Lesson
ALWAYS use health checks with `condition: service_healthy` for service dependencies. The depends_on without condition only waits for the container to start, NOT for the service to be ready.