Emmanuel Corels
← Blog
Containers & Kubernetes

Reach a host service from a Docker container—and prove where it fails

Inside a container, localhost means the container itself. Map the host gateway correctly, check the host binding and test DNS, TCP and HTTP as separate layers.

By Emmanuel Corels

Your application works at http://localhost:8000 on the host, but a container gets “connection refused.” Nothing mysterious happened: network namespaces changed what localhost means. Inside the container, 127.0.0.1 is the container’s own loopback interface—not the host’s.

Prove the host service before changing Docker

ss -ltnp | grep ':8000'
curl -v http://127.0.0.1:8000/health

Read the listening address. A service bound only to 127.0.0.1:8000 accepts host-loopback traffic and may reject traffic arriving through a bridge gateway. If container access is intended, bind the service to an appropriate host interface, commonly 0.0.0.0 or the bridge address, and enforce exposure with the firewall. Do not widen a production listener without reviewing the security boundary.

Docker Desktop: use the provided DNS name

docker run --rm curlimages/curl:latest   -v http://host.docker.internal:8000/health

Docker Desktop provides host.docker.internal for reaching the host-side environment. It is preferable to baking a changing private IP into application configuration.

Docker Engine on Linux: map the host gateway

docker run --rm   --add-host host.docker.internal:host-gateway   curlimages/curl:latest   -v http://host.docker.internal:8000/health

Docker’s daemon documentation defines host-gateway as a special value resolved to addresses on the host; by default it uses the default bridge gateway. For Compose:

services:
  app:
    image: example/app:1.4
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      API_BASE_URL: "http://host.docker.internal:8000"

Recreate the container after changing Compose configuration, then confirm the injected mapping:

docker compose up -d --force-recreate app
docker compose exec app getent hosts host.docker.internal
docker compose exec app cat /etc/hosts

Test one network layer at a time

# 1. Name resolution
getent hosts host.docker.internal

# 2. TCP reachability
nc -vz host.docker.internal 8000

# 3. HTTP exchange
curl -sv --connect-timeout 3   http://host.docker.internal:8000/health
ResultLikely boundaryNext check
Name not foundHost mapping or container DNSInspect extra_hosts and recreate the container
Connection refusedNo listener on that address/portInspect host binding with ss
TimeoutFirewall, route or filtered trafficTrace rules and packets on the host
HTTP 401/403Network succeeded; application rejected requestCheck credentials and Host header

When host networking is appropriate

On supported Linux deployments, --network host places the container in the host network namespace, so host loopback semantics differ from bridge mode:

docker run --rm --network host   curlimages/curl:latest   -v http://127.0.0.1:8000/health

This removes network isolation and can create port collisions. It is not the universal “fix”; choose it only when the architecture calls for host networking and its security implications are understood.

A service-to-service container should usually use a Docker network

If the dependency can run in Compose, address it by service name rather than routing out to the host:

services:
  app:
    image: example/app:1.4
    environment:
      API_BASE_URL: "http://api:8000"
  api:
    image: example/api:2.1
    expose:
      - "8000"

Compose DNS resolves api on the shared network. This keeps the dependency explicit, portable and separate from the host’s incidental network state.

Close the investigation

Record the container image, network mode, resolved gateway, host listening address and exact curl result. A successful ping is not enough; many services or environments do not answer ICMP, and ping does not prove that the required TCP port or application route works.

“Localhost” names a network namespace, not the physical machine sitting in front of you.

Sources: the solved Stack Overflow question (question by Phil; accepted answer by Thomasleveil, CC BY-SA), Docker’s host-gateway documentation, and Compose networking documentation.

Primary source: Review the official reference ↗