Intro
Docker Compose simplifies multi-container application deployment by defining services, networks, and volumes in a single YAML file. However, when moving from development to production, networking issues often surface: containers cannot reach each other, DNS resolution fails, ports are not exposed correctly, or external traffic is blocked by firewalls. These problems can cause service outages and slow down incident response.
This guide provides practical, step-by-step methods to diagnose and resolve Docker Compose networking issues in production environments. You will learn how to inspect your Docker environment, verify DNS and connectivity, check firewall rules, and apply safe configuration changes with rollback options. Each section includes concrete commands and expected outputs so you can follow along and adapt them to your setup.
By the end of this guide, you will have a repeatable troubleshooting workflow that reduces downtime and builds confidence in your Docker Compose deployments.
Version and Environment Inventory
Before troubleshooting, gather precise information about your Docker and Compose versions, network topology, and running containers. This baseline helps identify version-specific bugs and ensures you apply compatible fixes.
Check Docker and Docker Compose Versions
Run the following commands to see installed versions:
docker --version
docker compose version
Example output:
Docker version 24.0.7, build afdd53b
Docker Compose version v2.21.0
Note: Docker Compose v2 is a plugin. If you use the older standalone docker-compose, the command is docker-compose --version. Knowing the exact version is crucial because networking behavior (especially DNS) changed between major versions.
List Running Containers and Networks
Inspect the current state of your deployment:
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
docker network ls
Example:
NAMES IMAGE STATUS PORTS
web nginx:alpine Up 2 hours 0.0.0.0:80->80/tcp
app myapp:latest Up 2 hours 8000/tcp
db postgres:15 Up 2 hours 5432/tcp
NETWORK ID NAME DRIVER SCOPE
abc123def456 bridge bridge local
ghi789jkl012 myapp_default bridge local
The myapp_default network is typically created by Docker Compose for your project. Note which containers are attached to which networks using docker network inspect.
Check Docker Compose File and Environment
Review your docker-compose.yml or docker-compose.yaml for network definitions and service dependencies. Also check for environment variable substitutions that might affect ports or network settings.
Example snippet:
services:
app:
build: .
ports:
- "${APP_PORT:-8000}:8000"
environment:
DB_HOST: db
depends_on:
- db
db:
image: postgres:15
volumes:
- db_data:/var/lib/postgresql/data
networks:
- backend
networks:
backend:
driver: bridge
Ensure the Compose file version is compatible with your Docker Engine. Docker Compose v2 ignores the version key, so it's optional.
Prerequisites for Troubleshooting
- Shell access to the Docker host with sufficient permissions (typically sudo or being in the docker group).
- Basic understanding of Linux networking commands (
ip,ss,ping,curl,dig). - A recent backup of your Docker Compose configuration and persistent volumes (for rollback if needed).
- Network access to the host and, if applicable, cloud provider firewall settings.
Safe Configuration Path
When applying network changes in production, follow a scoped approach: make minimal, reversible changes and test after each step. Avoid broad modifications that affect multiple services simultaneously.
Understand Docker Compose Networking Basics
Docker Compose creates a default network for each project (named <project>_default). Containers can reach each other by service name (which is also the container name) due to embedded DNS. For explicit control, define custom networks.
Example of a custom network with a subnet:
networks:
backend:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
Avoid using the default network in production if you need IP range control or network isolation.
Verify DNS Resolution Inside Containers
Docker's embedded DNS server at 127.0.0.11 resolves container names. Test from inside a container:
docker exec -it app nslookup db
Expected output:
Server: 127.0.0.11
Address: 127.0.0.11#53
Name: db
Address: 172.28.0.3
If DNS fails, check that both containers are on the same custom network. Containers on different networks cannot resolve each other by name unless you use a network alias or connect them via an external network.
Check Port Publishing and Binding
Port publishing maps a host port to a container port. Use docker port to verify:
docker port <container_name>
Example:
80/tcp -> 0.0.0.0:80
80/tcp -> :::80
This shows that host port 80 is forwarded to container port 80. If you need to change the host port, edit the Compose file ports section and run docker compose up -d to recreate the container.
Important: Changing ports may disrupt existing connections. Always test the new port before removing the old one. You can temporarily expose both ports:
ports:
- "8080:80"
- "80:80"
Then migrate traffic and remove the old port.
Use Environment Variables for Configuration
Hardcoding IP addresses and ports makes troubleshooting harder. Use environment variables with sensible defaults.
In Compose file:
services:
app:
environment:
DB_HOST: ${DB_HOST:-db}
DB_PORT: ${DB_PORT:-5432}
In .env file:
DB_HOST=db
DB_PORT=5432
This allows quick changes without editing the Compose file and is safer for production.
Avoid Host Networking Mode
Unless absolutely necessary, avoid network_mode: host because it bypasses Docker's network isolation and can cause port conflicts. Prefer bridge networks for better control and security.
Verification and Diagnostics
After any configuration change, verify connectivity and performance. This section provides commands and expected outputs to confirm that networking is functioning correctly.
Test Inter-Container Communication
From within a container, use ping (if available) or curl to reach another service. Many minimal images lack ping; use wget or a simple TCP check.
Example:
docker compose exec app sh -c "wget -qO- http://db:5432/ || echo 'Connection failed'"
For a TCP port check without extra tools, use nc (netcat) if present, or install it temporarily (not recommended in production). Instead, use docker run with a temporary container on the same network:
docker run --rm -it --network myapp_default alpine sh -c "apk add --no-cache busybox-extras && telnet db 5432"
Expected output if connection succeeds:
Connected to db
If it times out, check the service's listening interface. For example, if a database is configured to listen only on localhost inside the container, it won't accept connections from other containers. The fix is to configure the service to listen on 0.0.0.0.
Diagnose DNS Issues
If service names do not resolve, inspect the DNS configuration inside the container:
docker exec -it app cat /etc/resolv.conf
Expected:
nameserver 127.0.0.11
options ndots:0
If it shows a different nameserver (like 8.8.8.8), Docker's embedded DNS is not being used, possibly because you set dns in the Compose file or the container uses a custom network with DNS overridden.
Check network connectivity to the Docker DNS:
docker exec -it app sh -c 'echo -e "GET / HTTP/1.0\r\n\r\n" | nc 127.0.0.11 53'
This is not a standard DNS query, but it verifies the port is reachable. For a real test, use dig if available:
docker exec -it app dig db @127.0.0.11
Verify External Connectivity
To test outbound internet access from a container:
docker exec -it app wget -qO- http://example.com
If this fails, check the host's firewall and IP forwarding. On Linux, ensure IP forwarding is enabled:
sysctl net.ipv4.ip_forward
Should output net.ipv4.ip_forward = 1. If not, enable it temporarily:
sudo sysctl -w net.ipv4.ip_forward=1
To make permanent, add net.ipv4.ip_forward=1 to /etc/sysctl.conf or a file in /etc/sysctl.d/.
Check Firewall Rules
Firewalls (host-based like iptables, or cloud security groups) often block Docker traffic. Docker manipulates iptables automatically, but manual rules can interfere.
List iptables rules for the DOCKER chain:
sudo iptables -L DOCKER -n -v
Example snippet:
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT tcp -- !br-abc123def456 br-abc123def456 0.0.0.0/0 172.28.0.2 tcp dpt:5432
This shows that traffic to the database container on port 5432 is allowed. If no rule exists, Docker may be unable to route.
For cloud environments, check security groups or firewall settings to ensure the required ports (e.g., 80, 443) are open from the internet or specific IP ranges.
Examine Docker Network Configuration
Inspect the network to see connected containers and IP addresses:
docker network inspect myapp_default
Output includes a list of containers with their IPv4 addresses. Verify that the IPs are within the expected subnet and that each container has a unique IP.
Monitor Logs for Network Errors
Container logs often reveal connection issues:
docker logs --tail 50 app
Look for errors like "connection refused", "name resolution failed", or "timeout". Adjust the tail number based on the log volume.
Failure Modes and Recovery
Even with careful planning, networking issues can occur. This section outlines common failure modes, their impact, and how to recover safely.
Common Failure Modes
- DNS Resolution Failure
- Symptom: Application logs show
getaddrinfo ENOTFOUND dbor similar. - Cause: Containers not on same network, custom DNS settings, or service name mismatch.
- Recovery: Ensure both containers are attached to the same network (or an external network). Check networks in Compose file. If using custom DNS, remove or adjust the
dnsoption.
- Port Binding Conflict
- Symptom:
docker compose upfails withBind for 0.0.0.0:80 failed: port is already allocated. - Cause: Another process on the host is using port 80, or a previous container still holds it.
- Recovery: Identify the process with
sudo lsof -i :80orsudo ss -tulpn | grep :80. Stop the conflicting process or change the host port in Compose.
- Container Cannot Reach External Network
- Symptom: Outbound requests from container time out.
- Cause: IP forwarding disabled, iptables misconfiguration, or Docker daemon not started correctly.
- Recovery: Enable IP forwarding as shown earlier. Restart Docker daemon (
sudo systemctl restart docker) after ensuring no critical containers are running (usedocker compose downfirst if needed).
- Inter-Container Communication Works by IP but Not by Name
- Symptom:
ping 172.28.0.3works butping dbfails. - Cause: Custom
/etc/hostsentries in container overriding Docker DNS, ornetwork_modeset incorrectly. - Recovery: Remove any manual
/etc/hostsmodifications and ensure the container is on the docker network. Usedocker execto check/etc/hosts; it should contain the container's own IP and hostname, but not entries for other services (Docker DNS handles those).
- Firewall Blocking Specific Ports
- Symptom: Host can reach container port internally, but external clients cannot.
- Cause: Security group or host firewall blocking the published port.
- Recovery: Update cloud security group to allow ingress on the port, or add iptables rules. For example, to allow port 8080:
sudo iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
Note: This rule is not persistent; use your distribution's firewall management tool (e.g., ufw allow 8080/tcp).
Rollback Strategies
Always have a rollback plan before making network changes.
- Keep previous Compose file: Before editing, copy
docker-compose.ymltodocker-compose.yml.bak. If changes break networking, restore anddocker compose up -d. - Use version control: Store Compose files in Git. Rollback via
git checkoutand redeploy. - For port changes: Keep the old port mapped temporarily until the new port is confirmed working. Example:
ports:
- "80:80" # old
- "8080:80" # new
Once verified, remove the old mapping and update load balancer accordingly.
- For network reconfiguration: If you need to change network subnet, first create a new network and gradually move services. Docker may require container recreation, so plan for brief downtime.
Verification After Recovery
After applying a fix, always verify:
docker compose psshows all services up and healthy.- DNS resolution works:
docker exec app nslookup db. - Port connectivity:
curl -I http://localhost:80from host. - Application logs show no new errors.
Common Pitfalls and How to Avoid Them
Even experienced operators hit recurring snags with Docker Compose networking. Here are common pitfalls and how to steer clear of them.
Forgetting to Attach Services to the Same Custom Network
By default, Compose creates a network per project, but if you define multiple networks and forget to list a service under networks, it may be left on the default network. Then other services cannot resolve it by name. Always explicitly define and attach services to the intended networks.
Overriding Docker's DNS Unintentionally
Setting dns or dns_search in the Compose file for a service replaces Docker's embedded DNS, breaking internal name resolution. Only override DNS if you need external DNS servers; then ensure internal names are still resolvable via extra_hosts or network aliases.
Using network_mode: host for Convenience
Host mode bypasses Docker networking, which can cause port conflicts and security issues. It also makes the container dependent on the host's network stack. Use bridge networks unless there is a specific reason, such as needing low-latency access to host services.
Not Checking IP Forwarding
Without IP forwarding enabled, containers cannot reach the external network even if the firewall is correct. Many minimal Linux distributions disable it by default. Always verify sysctl net.ipv4.ip_forward after kernel updates or system reboots.
Ignoring Cloud Security Groups
Docker's iptables rules control traffic on the host, but cloud providers add another layer. A port might be published correctly but still blocked by the security group. Always check both layers when external access fails.
Hardcoding IP Addresses
Using fixed IP addresses in application configuration or Compose files leads to breakage when containers are recreated with new IPs. Rely on DNS service names and use environment variables for any external dependencies.
Not Testing Rollback Procedures
A rollback plan is only as good as its last test. Regularly simulate a failed deployment and practice restoring from backup. This ensures your team can act quickly under pressure.
Operations Checklist
Use this checklist before and after any network change in Docker Compose production. Each item has an accountable owner and a review frequency.
| Step | Action | Command / Check | Owner | Review Frequency |
|---|---|---|---|---|
| 1 | Backup Compose file | cp docker-compose.yml docker-compose.yml.bak | Priya Shah, Engineering Lead | Before every change |
| 2 | Record current state | docker ps, docker network ls | Priya Shah | Before and after change |
| 3 | Test DNS resolution | docker exec <container> nslookup <service> | Alex Rivera, DevOps Engineer | After every change |
| 4 | Verify port bindings | docker port <container> | Alex Rivera | After every change |
| 5 | Check firewall rules | sudo iptables -L DOCKER -n -v | Maria Gomez, Security Specialist | Monthly and after firewall changes |
| 6 | Enable IP forwarding | sysctl net.ipv4.ip_forward | Alex Rivera | After every reboot |
| 7 | Apply configuration change | Edit file, docker compose up -d | Priya Shah | As needed |
| 8 | Verify after change | Repeat steps 2-6, check logs | Alex Rivera | Immediately after change |
| 9 | Update rollback plan | Document the change and how to revert | Priya Shah | After every change |
| 10 | Monitor for regressions | docker logs --tail 100 <service> | Priya Shah | Weekly |
Conclusion
Troubleshooting Docker Compose networking in production requires a systematic approach: understand your environment, apply safe changes, verify with concrete commands, and be ready to roll back. By following the steps in this guide, you can quickly identify DNS misconfigurations, port conflicts, firewall blocks, and routing problems.
Remember to keep your Compose files version-controlled, use environment variables for flexibility, and test changes in a staging environment whenever possible. The first pilot of any network change should be narrow and measurable, allowing you to inspect results locally before scaling.
Use the operations checklist as a routine practice before and after deployments. With these tools, you can minimize downtime and maintain reliable Docker Compose production services.
Next steps: Start by inventorying your current Docker environment. Run the version and network commands to establish a baseline. Then, test your inter-container DNS and connectivity. If issues arise, apply the diagnostics in order, and always have a rollback plan ready.