What this usually means
Inside a Docker container, `localhost` means the container itself, not your host machine. When your app code calls `localhost:5432`, it is looking for a service running inside the same container. Unless you run your database inside that container, nothing is listening there. Docker containers run on an isolated network. To reach a service on the host, you need to use the special DNS name `host.docker.internal` (macOS/Windows) or the host's IP on the Docker bridge network (Linux).
The first ten minutes \u2014 establish facts before touching code.
- 1Confirm the service is running on the host: `curl localhost:5432` or `nc -zv localhost 5432` from outside Docker.
- 2Inside the container, try reaching the host: `docker exec <container> ping host.docker.internal`. If it resolves, use that hostname.
- 3Check the container's network mode. `docker run --network host` removes network isolation but has trade-offs.
- 4If using docker-compose, check the service name. Containers in the same compose network reach each other by service name, not localhost.
- 5Verify the service is listening on `0.0.0.0` not just `127.0.0.1`. A service bound to 127.0.0.1 only accepts connections from the same machine.
The specific files, logs, configs, and dashboards that usually own this bug.
- searchDocker run command or docker-compose.yml — network mode and port mappings
- searchThe host service's bind address (`netstat -an`, `ss -tlnp`) — must be 0.0.0.0 to accept Docker connections
- searchContainer shell: `docker exec -it <container> sh` — test connectivity with curl, ping, nc
- searchDocker networking docs — `host.docker.internal` availability per platform
- searchFirewall rules — host firewall may block Docker bridge network traffic
Practical causes, not theory. These are the things you will actually find.
- warningService on host is bound to 127.0.0.1 only, rejecting Docker bridge network connections
- warningUsing `localhost` or `127.0.0.1` in connection strings inside the container
- warning`host.docker.internal` not available on Linux (requires Docker 20.10+ with `--add-host` flag)
- warningDocker container is on a different network than expected (custom bridge vs default bridge)
- warningHost firewall blocks the Docker bridge IP range
- warningPort mapping is wrong or missing in `docker run -p` or compose `ports` section
Concrete fix directions. Pick the one that matches your root cause.
- buildUse `host.docker.internal` instead of `localhost` for host services (macOS/Windows)
- buildOn Linux, add `--add-host=host.docker.internal:host-gateway` to `docker run` or use the host's Docker bridge IP
- buildIn docker-compose, reference other services by their compose service name, not IP or localhost
- buildEnsure the host service binds to `0.0.0.0` or the Docker bridge interface, not only 127.0.0.1
- buildFor production, run dependent services (DB, cache) as containers in the same compose network — do not rely on host networking
A fix you cannot prove is a guess. Close the loop.
- verifiedFrom inside the container, run `curl host.docker.internal:<port>` or `nc -zv host.docker.internal <port>`. Confirm connection.
- verifiedCheck the host service logs show an incoming connection from the Docker container.
- verifiedRun the full stack with docker-compose and verify all container-to-container connections work.
- verifiedTest from a second container on the same Docker network to rule out host-level firewall issues.
- verifiedDocument the networking setup so the next developer does not spend an hour on this again.
Things that make this bug worse or harder to find.
- warningUsing `--network host` as a permanent fix — it breaks container isolation and portability
- warningHardcoding the host's IP address instead of using DNS names or compose service names
- warningAssuming `host.docker.internal` works on all Linux distributions without extra configuration
- warningForgetting that each container has its own loopback interface
- warningNot checking the service bind address before debugging Docker networking