Intro
When a container cannot reach another container, the outside world, or a DNS name, the cause can hide in Docker's layered networking model. This guide provides a practical, command-first approach to troubleshooting Docker networking. It is built for developers, DevOps engineers, and technical startup teams who need to move from "it does not work" to a verified fix without guesswork.
We focus on four recurring failure areas: DNS resolution, published ports, container-to-container connectivity, and general network misconfiguration. Each section pairs commands, expected outputs, failure signals, and recovery steps. The goal is operational safety: observe before changing, limit blast radius, use placeholders instead of secrets, verify results, and document recovery paths.
Docker networking is not one thing. It is a stack of choices: bridge networks, overlay networks, host networking, custom DNS, iptables rules, and user-defined networks. A methodical approach prevents you from changing things blindly. We start with an environment inventory and then move through specific diagnostic workflows.
Version and Environment Inventory
Before troubleshooting, know your environment. The Docker version, storage driver, network plugins, and container runtime all influence how networking behaves. A mismatch between Docker versions or a missing kernel module can cause issues that look like application bugs.
Run these read-only commands first to capture the current state:
docker version
This shows the client and server versions. If they differ significantly, some features may not work. For example, overlay networks require Docker Engine 1.12 or later. Copy the output into your notes.
docker info
Look for the "Storage Driver", "Network", and "Kernel Version" lines. The "Network" line shows available network drivers (e.g., bridge, overlay, macvlan). If a driver is missing, containers using it will fail to start.
Next, list running containers and their health:
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
The output might look like this:
NAMES STATUS PORTS
web Up 2 minutes 0.0.0.0:8080->80/tcp
db Up 2 minutes 3306/tcp
cache Exited (1) 10 seconds ago
Notice that cache has exited. If a container exited, check its logs:
docker logs cache --tail 100
If you need full configuration details, use inspect:
docker inspect web
This returns a JSON object with networking, mounts, environment variables, and health status. To extract just the network settings:
docker inspect web --format '{{json .NetworkSettings}}' | jq
For Docker Compose projects, these commands are equivalent and often easier:
docker compose ps
docker compose logs -f web
docker compose exec db sh
Using docker compose exec lets you debug inside a container without modifying the image. However, note that the container must be running.
When data is involved, confirm where files are stored before changing containers. A named volume such as app_data:/var/lib/app is managed by Docker and is usually easier to reuse across container rebuilds. A bind mount such as ./data:/var/lib/app maps a host directory directly and is useful for local development, but it can expose permission, portability, and backup problems if the same path does not exist on another machine.
A small production-like local test should include a restart test: stop the container, recreate it, and confirm the application still sees the expected files. If the data disappears, the service was probably writing to the container filesystem instead of a volume or mount.
Safe Configuration Path
Once you understand the current state, make changes carefully. Docker networking configuration is often global or per-network. A wrong change can disrupt all containers on a host.
Isolate the Network
Before changing anything, identify the network(s) involved. List all networks:
docker network ls
Typical output:
NETWORK ID NAME DRIVER SCOPE
abc123def456 bridge bridge local
def456abc789 host host local
789def456abc none null local
123abc789def myapp bridge local
The default networks (bridge, host, none) are always present. Custom networks like myapp are usually created by the user or by Compose.
Inspect the network to see containers attached and subnet details:
docker network inspect myapp
This yields JSON. Here is a compacted example showing the important fields:
[
{
"Name": "myapp",
"Id": "123abc789def...",
"Driver": "bridge",
"IPAM": {
"Driver": "default",
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Containers": {
"web_container_id": {
"Name": "web",
"IPv4Address": "172.18.0.2/16"
}
}
}
]
If the subnet overlaps with your host network or another Docker network, you will experience routing problems. In that case, create a new network with a non-overlapping subnet:
docker network create --subnet 192.168.100.0/24 --gateway 192.168.100.1 myapp_fixed
Then reconnect containers to the new network. For Compose, change the networks section in your docker-compose.yml and run docker compose up -d.
Change One Thing at a Time
Suppose a container cannot resolve a DNS name. You might be tempted to change the DNS server, edit /etc/hosts, and restart Docker all at once. Instead, follow a stepwise path:
- Check if the container can reach any network at all (ping an IP).
- Check if it can resolve a name (dig or nslookup).
- If not, inspect the DNS configuration inside the container.
- Change only the DNS setting (e.g., in the network or container configuration).
- Restart the container and re-test.
Each change should be reversible. Keep a command log. For example:
# Before change: container cannot resolve google.com
# Change: add dns option to container
docker run --dns 8.8.8.8 --name test busybox nslookup google.com
# After change: expected output shows IP address
If the change does not fix the issue, revert it and try the next hypothesis.
Verification and Diagnostics
This section provides specific diagnostic workflows for common Docker networking problems.
Problem 1: Container Cannot Reach the Internet
Symptoms: apt-get update fails, curl to external sites times out, but other containers on the same host may work.
Diagnostic steps:
- Test connectivity from inside the container to an external IP (bypass DNS):
docker exec -it web ping 8.8.8.8
Expected output if network is working:
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=117 time=10.5 ms
If ping fails, the container has no route to the internet. Check the host's routing and iptables rules.
- Test DNS resolution:
docker exec -it web nslookup google.com
Expected output:
Server: 127.0.0.11
Address: 127.0.0.11#53
Non-authoritative answer:
Name: google.com
Address: 142.250.72.14
If the IP address resolves, DNS works. If it fails with a timeout, DNS is broken.
- Inspect the container's DNS configuration:
docker exec -it web cat /etc/resolv.conf
On Docker's default bridge network, you will see:
nameserver 127.0.0.11
options ndots:0
The embedded DNS server at 127.0.0.11 forwards queries to the host's DNS servers. If you have a custom network, you can set a different DNS:
docker network create --dns 1.1.1.1 mynet
Or when running a container:
docker run --dns 1.1.1.1 --name test busybox nslookup google.com
Recovery:
- If the host itself cannot reach the internet, fix the host network first.
- If DNS is misconfigured, adjust the DNS settings on the network or container.
- If iptables rules are blocking, check
iptables -L -n -vand Docker's NAT rules.
Problem 2: Published Port Not Accessible from Host
Symptoms: You mapped a port with -p 8080:80, but curl localhost:8080 on the host fails.
Diagnostic steps:
- Verify the container is running and ports are mapped:
docker ps --format "{{.Names}}\t{{.Ports}}"
Expected output shows 0.0.0.0:8080->80/tcp. If the mapping is missing, the container was not started with the -p flag.
- Check if the service inside the container is listening:
docker exec web netstat -tulpn | grep 80
Expected output:
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
If nothing listens on port 80, the application inside is not running correctly.
- Check the host's iptables:
sudo iptables -t nat -L -n | grep 8080
You should see a DNAT rule forwarding port 8080 to the container's IP and port 80.
Recovery:
- If the port mapping is wrong, recreate the container with the correct
-pflag. - If the service is not listening, fix the application.
- If iptables rules are missing, restart Docker or manually add rules.
Problem 3: Containers on the Same Network Cannot Communicate
Symptoms: Two containers on a user-defined network cannot ping each other by name or IP.
Diagnostic steps:
- Confirm both containers are attached to the same network:
docker network inspect myapp --format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'
Expected output lists both containers with IPs.
- Test connectivity by IP:
docker exec web ping 172.18.0.3
If this works, IP connectivity is fine; the issue is name resolution.
- Test by container name:
docker exec web ping db
If name resolution fails, check the embedded DNS. On user-defined networks, Docker's embedded DNS should resolve container names to IPs automatically.
Recovery:
- If IP ping fails, check if the containers are on the same network or if there is an iptables rule blocking traffic.
- If name resolution fails, ensure the container names are unique and the network is user-defined (not the default bridge, which does not provide automatic DNS).
Problem 4: DNS Resolution Fails for Custom Domains
Symptoms: Containers cannot resolve a domain that points to a service inside the Docker network (e.g., api.internal).
Diagnostic steps:
- Check the DNS configuration:
docker exec web cat /etc/resolv.conf
The embedded DNS at 127.0.0.11 only resolves container names on user-defined networks, not arbitrary custom domains.
- Set a custom DNS server or add host entries.
For a custom DNS server:
docker network create --dns 192.168.1.10 mynet
To add a host entry:
docker run --add-host api.internal:192.168.1.20 --name test busybox cat /etc/hosts
Recovery:
- Use
--dnsfor network-wide DNS. - Use
--add-hostfor static host mappings per container. - Or run a local DNS server as a container and point other containers to it.
Failure Modes and Recovery
Here are common failure modes, their symptoms, and recovery strategies.
1. IP Address Exhaustion
Symptom: New containers fail to start with an error like failed to allocate IP address or no available addresses on network.
Why it happens: The default bridge network uses a /16 subnet (172.17.0.0/16), which allows 65,534 addresses, but a custom network may have a smaller subnet. If you have many containers or frequently recreate them, you may exhaust the pool.
How to recover:
- Check the subnet and used IPs:
docker network inspect myapp --format '{{.IPAM.Config}}'
- Increase the subnet size by creating a new network with a larger subnet, then reconnect containers.
- Remove stale containers that hold IPs.
2. DNS Resolution Timeouts
Symptom: Name resolution hangs and then times out.
Why it happens: The embedded DNS server forwards queries to the host's DNS servers. If the host DNS is slow or unreachable, all container DNS resolution will be slow. Also, ndots settings may cause extra lookups.
How to recover:
- Check host DNS configuration:
cat /etc/resolv.confon the host. - Specify a faster DNS server for Docker networks:
docker network create --dns 1.1.1.1 --dns 8.8.8.8 mynet. - For containers, use
--dnsflag.
3. Network Overlap
Symptom: Containers can reach some IPs but not others; routing is inconsistent.
Why it happens: Docker's default subnets (172.17.0.0/16, 172.18.0.0/16, etc.) may overlap with your organization's internal networks. Traffic may be routed incorrectly.
How to recover:
- Identify the overlap by comparing Docker network subnets with your internal subnets.
- Create a new Docker network with a non-overlapping subnet, e.g.,
10.100.0.0/16. - Update your application configuration to use the new network.
4. Container Cannot Reach Host Services
Symptom: A container cannot connect to a service running on the host (e.g., a database on localhost).
Why it happens: On the default bridge network, the host is reachable at the gateway IP (usually 172.17.0.1), but localhost inside the container refers to the container itself.
How to recover:
- Use the special hostname
host.docker.internal(on Docker Desktop for Mac/Windows) or the gateway IP to reach the host. - For Linux, add
--add-host=host.docker.internal:host-gatewayto yourdocker runcommand.
5. Firewall Blocking Container Traffic
Symptom: External clients cannot reach published ports, even though docker ps shows the port mapping.
Why it happens: The host firewall (e.g., UFW, firewalld) may block incoming connections to the published port. Docker manipulates iptables directly, which can conflict with firewall rules.
How to recover:
- Check firewall status:
sudo ufw statusorsudo firewall-cmd --list-all. - Open the necessary port:
sudo ufw allow 8080/tcp. - Adjust Docker's iptables integration if needed (usually not recommended unless you know what you are doing).
Operations Checklist
Use this checklist for day-to-day Docker networking operations. Each item includes the responsible role and how often to review.
| Item | Command or Action | Owner | Frequency |
|---|---|---|---|
| Verify Docker version and network drivers | docker version, docker info | DevOps Engineer | Monthly |
| List running containers and port mappings | docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | On-call engineer | Daily health check |
| Check network configuration | docker network ls, docker network inspect <net> | DevOps Engineer | When network changes |
| Test container-to-container connectivity | docker exec <container> ping <other-container> | On-call engineer | As needed |
| Validate DNS resolution | docker exec <container> nslookup google.com | On-call engineer | As needed |
| Review port publishing rules | sudo iptables -t nat -L -n -v | Security/Network admin | Quarterly |
| Test restart recovery | Stop and start containers, verify data persistence | DevOps Engineer | Before each release |
| Update firewall rules | sudo ufw status, open necessary ports | Network admin | When ports change |
| Clean up unused networks and containers | docker network prune, docker container prune | DevOps Engineer | Monthly |
For each major decision, such as changing a network subnet or adding a new network, assign a single accountable owner. For example, the DevOps Engineer owns the network design, and the on-call engineer owns immediate fixes. Review the network configuration at least quarterly or after any significant incident.
Common Pitfalls and How to Avoid Them
Pitfall 1: Using the Default Bridge for Container Communication
Problem: Containers on the default bridge network can communicate via IP but not by name, because the default bridge does not provide automatic DNS resolution.
Why it happens: Many tutorials use the default bridge for simplicity, but it lacks the DNS service available on user-defined networks.
How to avoid: Always create a user-defined bridge network for your application:
docker network create myapp
Then run containers with --network myapp. In Compose, define a custom network.
Pitfall 2: Assuming localhost Inside the Container Refers to the Host
Problem: Developers often try to connect to a host service using localhost from inside a container and fail.
Why it happens: Each container has its own network namespace, so localhost is the container itself.
How to avoid: Use the gateway IP or host.docker.internal as described earlier. For example, in Docker Desktop, connect to host.docker.internal:5432 for a host Postgres.
Pitfall 3: Misconfigured Port Bindings
Problem: Binding to the wrong interface or using the wrong ports.
Why it happens: By default, Docker publishes ports on all interfaces (0.0.0.0). If you want to restrict access, you must specify the host IP.
How to avoid: Explicitly bind to the desired interface:
docker run -p 127.0.0.1:8080:80 nginx
This restricts access to localhost only.
Pitfall 4: Ignoring Network Driver Limitations
Problem: Trying to use overlay networks without swarm mode or a key-value store.
Why it happens: Overlay networks are designed for multi-host networking and require swarm mode or an external key-value store (for older Docker versions).
How to avoid: Use overlay networks only in swarm mode or with appropriate configuration. For single-host, use bridge or macvlan drivers.
Pitfall 5: Not Cleaning Up Networks
Problem: Accumulated unused networks lead to confusion and IP conflicts.
Why it happens: Networks are not automatically removed when containers are removed.
How to avoid: Periodically prune unused networks:
docker network prune
This removes all networks not used by at least one container. Use docker network ls to review before pruning.
Conclusion
Docker networking troubleshooting is a systematic process of observation, targeted change, and verification. By following the inventory and diagnostic steps in this guide, you can resolve most issues without guesswork. The key is to understand Docker's networking model: user-defined bridge networks with built-in DNS, port publishing via iptables, and the differences between container and host network namespaces.
As a next step, choose one low-risk verification from the checklist, record the current state, run the documented check, compare the result with the expected signal, and review dependencies. A reliable technical workflow makes failure visible, protects sensitive values, limits changes to the intended resource, and defines recovery verification before an incident forces the decision.
Remember to assign clear ownership for network changes and to review your network configuration regularly. With these practices, you can keep your Docker environments stable and your applications connected.