How to fix dial tcp: connect: no route to host in Docker

DockerINTERMEDIATEMEDIUMUpdated Dec 6, 2025· 380 views

This error occurs when a Docker container cannot establish a network connection to a target host. It's typically caused by firewall rules blocking container traffic, incorrect network configuration, or the target host being unreachable from the container's network namespace.

Quick fix

Fixes dial tcp: connect: no route to host

# Enable masquerading for NAT from containers
sudo firewall-cmd --zone=public --add-masquerade --permanent

# Reload firewall to apply changes
sudo firewall-cmd --reload

# Restart Docker to re-establish network rules
sudo systemctl restart docker
  1. Configure firewalld to allow Docker container traffic
  2. Add Docker subnet to firewall trusted zone
  3. Use iptables rules for finer control
  4. Remove conflicting Docker networks
docker — error
# Enable masquerading for NAT from containers
sudo firewall-cmd --zone=public --add-masquerade --permanent
# Reload firewall to apply changes
sudo firewall-cmd --reload
# Restart Docker to re-establish network rules
sudo systemctl restart docker
dial tcp: connect: no route to host

What this error means

The "dial tcp: connect: no route to host" error indicates that your Docker container is attempting to make a TCP connection to another host (either the Docker host, another container, or an external service) but the network layer is reporting that no route exists to reach the destination. This error is different from "connection refused" - a "no route to host" error means the network packets cannot even reach the destination, whereas "connection refused" means packets arrived but nothing was listening. This distinction is important for troubleshooting. This error commonly appears in several scenarios: - **Container-to-host communication**: A container trying to connect to a service running on the Docker host via the host's IP address - **Container-to-container communication**: One container trying to reach another container via published ports on the host IP - **Registry access**: Docker pull/push operations failing to reach a private registry in your network - **External service access**: Containers unable to reach external APIs, databases, or services - **CI/CD pipelines**: Build or test steps failing to connect to required services The root cause is almost always related to firewall configuration (especially firewalld on RHEL/CentOS/Fedora), Docker network configuration, or routing table issues.

Typical symptoms

  • Docker commands fail with 'dial tcp: connect: no route to host'
  • Container can ping the target IP but TCP connections fail
  • Docker pull fails when accessing a private registry on the local network
  • Container-to-container communication via host IP fails while direct network works
  • Services work when run directly on host but fail when containerized
  • The error only occurs for certain ports while ICMP (ping) works fine
  • Problem appears after system updates or firewall configuration changes

Common causes

  1. Firewall (firewalld) blocking traffic from Docker's bridge network to the host
  2. Missing masquerade rule in firewall preventing container NAT traffic
  3. Docker network subnet conflicts with existing network routes
  4. Conflicting MAC addresses when using multiple Docker networks in compose
  5. iptables rules dropping packets from Docker bridge interfaces
  6. Target service bound only to localhost (127.0.0.1) instead of all interfaces
  7. VPN or custom routing rules interfering with Docker network traffic
  8. SELinux policies blocking container network access
  9. Docker daemon network configuration issues after restart

How to fix "dial tcp: connect: no route to host"

1Configure firewalld to allow Docker container traffic

The most common cause of this error on RHEL, CentOS, Fedora, and similar systems is firewalld blocking container traffic. Add masquerade support to allow Docker containers to communicate with the host:

bash
# Enable masquerading for NAT from containers
sudo firewall-cmd --zone=public --add-masquerade --permanent

# Reload firewall to apply changes
sudo firewall-cmd --reload

# Restart Docker to re-establish network rules
sudo systemctl restart docker

Verify the masquerade is enabled:

bash
sudo firewall-cmd --zone=public --query-masquerade
# Should output: yes

This single fix resolves the majority of "no route to host" issues on systems running firewalld.

2Add Docker subnet to firewall trusted zone

If masquerade alone doesn't work, explicitly allow traffic from Docker's network subnets:

bash
# Allow all Docker network traffic (172.x.x.x range)
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family=ipv4 source address=172.0.0.0/8 accept'

# Or specifically for the default bridge network (172.17.0.0/16)
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family=ipv4 source address=172.17.0.0/16 accept'

# Reload to apply
sudo firewall-cmd --reload

Alternative: Add docker0 interface to trusted zone:

bash
sudo firewall-cmd --permanent --zone=trusted --change-interface=docker0
sudo firewall-cmd --reload

Note: If you're using custom Docker networks, they may use different subnets. Check your networks:

bash
docker network inspect bridge | grep Subnet
docker network ls
3Use iptables rules for finer control

If you need more granular control or firewalld's zone-based approach isn't working, use iptables directly:

bash
# Allow all traffic from Docker's default bridge subnet
sudo iptables -I INPUT 1 -s 172.17.0.0/16 -j ACCEPT

# Or for a specific port only (e.g., port 8080)
sudo iptables -I INPUT 1 -s 172.17.0.0/16 -p tcp --dport 8080 -j ACCEPT

# Allow forwarding for Docker
sudo iptables -I FORWARD 1 -i docker0 -j ACCEPT
sudo iptables -I FORWARD 1 -o docker0 -j ACCEPT

Make rules persistent (varies by distribution):

bash
# On RHEL/CentOS
sudo service iptables save

# On Ubuntu/Debian
sudo apt install iptables-persistent
sudo netfilter-persistent save

Check current iptables rules:

bash
sudo iptables -L -n -v | head -50
sudo iptables -t nat -L -n -v
4Remove conflicting Docker networks

MAC address conflicts between Docker networks can cause routing issues. If you're using docker-compose with multiple networks, try cleaning up:

bash
# List all Docker networks
docker network ls

# Remove unused networks (keeps bridge, host, none)
docker network prune

# Or remove specific networks
docker network rm <network_name>

Check for MAC address conflicts:

bash
# List all MAC addresses across all networks
docker network inspect $(docker network ls -q) | grep -i macaddress

For docker-compose, bring down and recreate networks:

bash
docker-compose down
docker-compose up -d

If the problem persists, try using a single network in your compose file instead of multiple custom networks.

5Test network connectivity from container

Debug the network issue from inside the container to understand what's happening:

bash
# Start a debug container with network tools
docker run --rm -it alpine sh

# Inside the container, install network tools
apk add --no-cache curl bind-tools iputils

# Test connectivity
ping -c 3 <target_ip>           # ICMP test
nc -zv <target_ip> <port>       # TCP port test
curl -v http://<target_ip>:<port>   # HTTP test
nslookup <hostname>             # DNS test

# Check routing table
ip route

From the host, verify the container's network:

bash
# Find the container's IP
docker inspect <container_id> | grep IPAddress

# Test connectivity to container from host
ping <container_ip>

If ping works but TCP fails, the issue is almost certainly firewall-related.

6Use host network mode as a workaround

If you need a quick workaround while debugging, run the container with host networking to bypass Docker's network namespace:

bash
# Run container with host network
docker run --network host <image>

# In docker-compose:
services:
  myservice:
    image: myimage
    network_mode: host

Important considerations:
- Host network mode removes network isolation between container and host
- Port conflicts can occur if container tries to bind to ports already in use
- This is a workaround, not a permanent solution
- Some features like port mapping (-p) don't work with host network mode

For testing purposes, this helps confirm whether the issue is network/firewall related.

7Check and fix service binding address

If a container is trying to reach a service on the Docker host, ensure the service is listening on the right interface:

bash
# Check what address the service is bound to
ss -tlnp | grep <port>
netstat -tlnp | grep <port>

If the output shows 127.0.0.1:<port>, the service is only listening on localhost and won't be reachable from containers.

Fix by binding to all interfaces (0.0.0.0):

For common services:

PostgreSQL (/etc/postgresql/*/main/postgresql.conf):

bash
listen_addresses = '*'

MySQL (/etc/mysql/mysql.conf.d/mysqld.cnf):

bash
bind-address = 0.0.0.0

Redis (/etc/redis/redis.conf):

bash
bind 0.0.0.0

Node.js/Express:

javascript
app.listen(3000, '0.0.0.0', () => {});

After changing the binding address, restart the service and ensure your firewall allows traffic to that port.

8Access host services using special DNS names

Instead of using the host's IP address, use Docker's built-in DNS names to reach the host:

Docker Desktop (Mac/Windows):

bash
# Use this hostname to reach the Docker host
curl http://host.docker.internal:<port>

Docker on Linux (20.10+):

bash
# Add host-gateway to your container
docker run --add-host=host.docker.internal:host-gateway <image>

# In docker-compose:
services:
  myservice:
    extra_hosts:
      - "host.docker.internal:host-gateway"

Alternative: Use bridge gateway IP:

bash
# Find the gateway IP (usually 172.17.0.1 for default bridge)
docker network inspect bridge | grep Gateway

# Use that IP to reach the host
curl http://172.17.0.1:<port>

Using these methods is more reliable than hardcoding the host's network IP address.

9Restart Docker daemon to reset network state

Sometimes Docker's network state becomes inconsistent. A clean restart can resolve routing issues:

bash
# Stop all containers gracefully
docker stop $(docker ps -q)

# Restart Docker daemon
sudo systemctl restart docker

# On systems without systemd
sudo service docker restart

# Verify Docker network rules are recreated
sudo iptables -L -n | grep -i docker
sudo iptables -t nat -L -n | grep -i docker

If problems persist, try a full network cleanup:

bash
# Stop Docker
sudo systemctl stop docker

# Remove Docker network interfaces (careful - this is disruptive)
sudo ip link delete docker0

# Restart Docker (it will recreate the interfaces)
sudo systemctl start docker

# Verify
ip addr show docker0

Check Docker daemon logs for network errors:

bash
sudo journalctl -u docker --since "10 minutes ago"

Advanced notes

Understanding Docker networking and firewalls:

Docker creates its own network infrastructure including bridge interfaces, iptables rules, and routing entries. When firewalld or iptables are running, they can interfere with Docker's networking in several ways:

- Zone processing order: firewalld processes zones by IP address before interface, which can cause unexpected behavior with Docker's bridge interface
- Masquerading: Docker containers need NAT to communicate with external networks. Without masquerade rules, outbound traffic appears to come from the container's private IP, which external hosts cannot route back to

Using firewalld direct rules:

When zone-based rules don't work reliably, firewalld direct rules are processed first and can be more effective:

bash
# Direct rule to allow traffic on docker0 interface
firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 10 -i docker0 -j ACCEPT
firewall-cmd --direct --permanent --add-rule ipv4 filter FORWARD 10 -i docker0 -j ACCEPT
firewall-cmd --reload

Diagnosing with packet tracing:

For complex network issues, trace packets through the system:

bash
# Watch for dropped packets
sudo iptables -I INPUT -j LOG --log-prefix "IPTables-Dropped: "
sudo journalctl -f | grep IPTables

# Use tcpdump on docker0 interface
sudo tcpdump -i docker0 host <target_ip>

# Check conntrack state
sudo conntrack -L | grep <target_ip>

SELinux considerations:

On systems with SELinux enforcing, container network access may be restricted:

bash
# Check for SELinux denials
sudo ausearch -m avc -ts recent | grep docker

# Temporarily set to permissive to test
sudo setenforce 0

# If that fixes it, create proper policies rather than disabling SELinux

Docker compose network isolation:

When using docker-compose, containers on the same compose network can communicate by service name. For external access via published ports, firewall rules still apply:

yaml
services:
  web:
    networks:
      - frontend
  api:
    networks:
      - frontend
      - backend
  db:
    networks:
      - backend

networks:
  frontend:
  backend:

Containers on different networks cannot communicate directly unless they share a network, regardless of firewall configuration.

Frequently asked questions

What does "dial tcp: connect: no route to host" mean?
The "dial tcp: connect: no route to host" error indicates that your Docker container is attempting to make a TCP connection to another host (either the Docker host, another container, or an external service) but the network layer is reporting that no route exists to reach the destination. This error is different from "connection refused" - a "no route to host" error means the network packets cannot even reach the destination, whereas "connection refused" means packets arrived but nothing was listening. This distinction is important for troubleshooting.
How do I fix "dial tcp: connect: no route to host"?
This error occurs when a Docker container cannot establish a network connection to a target host. It's typically caused by firewall rules blocking container traffic, incorrect network configuration, or the target host being unreachable from the container's network namespace.
What causes "dial tcp: connect: no route to host"?
Firewall (firewalld) blocking traffic from Docker's bridge network to the host Missing masquerade rule in firewall preventing container NAT traffic Docker network subnet conflicts with existing network routes
Is the "dial tcp: connect: no route to host" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading