Skip to content
DevOps AI ToolKit
Newsletter
All guides
Docker with AI By James Joyner IV · · 9 min read

Docker Error Guide: 'Connection refused' — Container Can't Reach the Host

Quick answer

Fix a Docker container that can't reach host or peer services: use host.docker.internal with host-gateway, pick bridge vs host networking, publish ports, and open the firewall.

Part of the Docker Container & Runtime Errors hub
  • #docker
  • #troubleshooting
  • #errors
  • #networking
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

A container cannot reach a service running on the Docker host, or on another container. Application code that connects to localhost or 127.0.0.1 typically fails like this:

curl: (7) Failed to connect to localhost port 5432 after 0 ms: Connection refused

The trap is that inside a container localhost means the container itself, not the host. So a process trying to reach a database on the host, or a peer container by IP, hits nothing and gets Connection refused (or No route to host / DNS Name does not resolve).

Symptoms

  • Connection refused when a container connects to localhost:<port> for a service that runs on the host.
  • One container can’t resolve another by name (could not translate host name "db" to address).
  • The service is published but still unreachable from outside — or reachable from the host but not the container.
  • ping to another container’s IP times out, or the host firewall silently drops the packets.

Common Root Causes

  • localhost confusion — the app targets 127.0.0.1, which is the container’s own loopback, not the host or a peer.
  • Missing host.docker.internal mapping — on Linux this name isn’t defined unless you add --add-host host.docker.internal:host-gateway.
  • Wrong network mode — containers on the default bridge network can’t resolve each other by name; only user-defined networks provide DNS.
  • Publish vs exposeEXPOSE/--expose only documents a port; you need -p/--publish to actually map it to the host.
  • Host firewall / iptables — the host’s firewall blocks the docker0 bridge or the published port.
  • Service binds to 127.0.0.1 on the host — a host service listening only on loopback is unreachable from containers even via host-gateway.

Diagnostic Workflow

Confirm which network the container is on and its IP:

docker inspect --format '{{json .NetworkSettings.Networks}}' web-1 | jq
docker network ls
docker network inspect bridge | jq '.[0].Containers'

Test reachability from inside the container — this is the key step:

docker exec web-1 sh -c 'nc -zv host.docker.internal 5432'
docker exec web-1 sh -c 'curl -fsS http://api-1:8080/healthz'
docker exec web-1 sh -c 'getent hosts api-1 || nslookup api-1'

To reach a service on the host, add the gateway mapping (Linux):

docker run --add-host host.docker.internal:host-gateway myapp:1.4.2
docker exec web-1 sh -c 'nc -zv host.docker.internal 5432'

For container-to-container name resolution, use a user-defined network instead of default bridge:

docker network create appnet
docker network connect appnet web-1
docker network connect appnet api-1
docker exec web-1 getent hosts api-1

Verify the port is actually published and the host is listening:

docker port web-1
sudo ss -tlnp | grep 5432        # is the host service on 0.0.0.0 or 127.0.0.1?

Check the host firewall if traffic still drops:

sudo iptables -L DOCKER-USER -n -v

Example Root Cause Analysis

An app in web-1 connects to postgres://localhost:5432 and logs Connection refused. Postgres runs on the host, not in a container.

From inside the container, docker exec web-1 nc -zv host.docker.internal 5432 fails with host.docker.internal: Name does not resolve — the container was started without the gateway mapping on Linux. Restarting with --add-host host.docker.internal:host-gateway and pointing the app at host.docker.internal:5432 gets past DNS, but nc now reports Connection refused.

sudo ss -tlnp | grep 5432 on the host shows Postgres bound to 127.0.0.1:5432 only. Because it listens on host loopback, the host-gateway route can’t reach it. Binding Postgres to 0.0.0.0:5432 (or the docker bridge IP) and allowing the subnet in pg_hba.conf — plus a DOCKER-USER iptables allow rule — makes nc -zv host.docker.internal 5432 succeed. Root cause: a real DNS gap and a host service on loopback, both required for the fix.

Prevention Best Practices

  • Put related containers on a user-defined network and address them by service name, never by localhost or hard-coded IP.
  • To reach the host from a container, use host.docker.internal and always pass --add-host host.docker.internal:host-gateway on Linux.
  • Ensure host services you need from containers bind to 0.0.0.0 (or the bridge IP), not 127.0.0.1.
  • Remember EXPOSE documents; -p host:container publishes. Publish only what you truly need externally.
  • Use --network host only when you deliberately want the container to share the host’s stack — it removes network isolation.
  • Add explicit DOCKER-USER iptables rules rather than relying on Docker’s defaults on locked-down hosts.

Quick Command Reference

# Networks and where the container sits
docker network ls
docker network inspect appnet | jq '.[0].Containers'

# Reach the host from inside a container (Linux)
docker run --add-host host.docker.internal:host-gateway myapp:1.4.2
docker exec web-1 nc -zv host.docker.internal 5432

# Container-to-container by name
docker network create appnet
docker network connect appnet web-1
docker exec web-1 getent hosts api-1

# Published ports and host listeners
docker port web-1
sudo ss -tlnp | grep 5432

# Firewall
sudo iptables -L DOCKER-USER -n -v

Conclusion

Container connectivity failures almost always come down to a naming or reachability mismatch: localhost inside a container is not the host, default bridge gives no name resolution, and a service bound to 127.0.0.1 is invisible across the bridge. Prove it from inside the container with docker exec … nc/curl, add host.docker.internal:host-gateway for host access, put peers on a user-defined network, and confirm the port is published and the firewall allows it. More networking recipes live in the Docker guides.

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.