Docker said 'healthy'. My app said 'connection refused'. 4 hours gone.
Last week I deployed something that should've been straightforward. Docker Compose, two containers, one talks to the other. Classic setup. Everything looked fine in docker ps. Both containers "healthy". Except my API couldn't reach the database and had no idea why.
What I saw
docker ps showed both containers up. Postgres on port 5432, my API on 3000. STATUS said "healthy" for both.
My app starts up, tries to connect to postgres:5432, and immediately throws "connection refused".
Tried localhost:5432. Tried 127.0.0.1:5432. Tried the container IP I found via docker inspect. Nothing worked.
What I did wrong first
Restarted everything. Updated docker-compose. Pulled fresh images. Wrote a test script to verify the port was open. That script worked fine when run locally but my actual app still couldn't connect.
At this point I'm googling "docker connection refused postgres" and trying every solution. Most of them assume you haven't already verified the port is accessible.
Then I noticed something in docker network inspect. My containers were on different networks.
The actual problem
My docker-compose had something like:
services:
api:
build: ./api
ports:
- "3000:3000"
networks:
- frontend
postgres:
image: postgres:15
ports:
- "5432:5432"
networks:
- backend
Api on frontend network. Postgres on backend network. They couldn't talk to each other even though both were running on the same Docker host.
The health check passed because it was just checking if postgres process was alive, not whether other containers could reach it.
The fix
services:
api:
build: ./api
ports:
- "3000:3000"
networks:
- frontend
- backend
depends_on:
- postgres
postgres:
image: postgres:15
ports:
- "5432:5432"
networks:
- backend
networks:
frontend:
backend:
Put both on the same network. Restarted. Worked immediately.
The kicker
Docker Compose doesn't automatically put all containers on the same network. Each service only gets a network if you explicitly assign it. If you add a service without specifying networks, you get whatever the default is. And if you have multiple services with no explicit assignment, they might not share a network depending on how your Compose file is structured.
Health checks lie sometimes too. A container can be "healthy" while the actual application inside it can't do its job. The health check is scoped to what you tell it to check, not real world connectivity.
"Connection refused" is technically accurate but not that helpful when you're debugging across multiple layers. Wrong port, wrong host, network isolation. All give you the same error.
Been explicit with networks ever since. Every service gets assigned, nothing is left to defaults. Learned this one the hard way.
Top comments (0)