App can't reach its database: it connects to 127.0.0.1, not the service name
Medium

Problem

The app service is up but can't reach its database. Its log repeats:

could not connect to server: Connection refused
  Is the server running on host "localhost" (127.0.0.1) and accepting
  TCP/IP connections on port 5432?

The db container is Up and healthy. Both containers are running on the same Docker network — they just aren't connecting. Find out why and state the fix.

Initial setup

  • appwebapp:3.1 (python), Up 20 minutes, retrying its DB connection.
  • dbpostgres:15-alpine, Up 1 hour, ready to accept connections.
  • Both are on the user-defined network appnet.

Example interaction

$ docker ps
# app and db are BOTH Up   (the DB is not down)

$ docker exec app nc -zv 127.0.0.1 5432
nc: connect to 127.0.0.1 (127.0.0.1) port 5432 (tcp) failed: Connection refused

$ docker exec app nc -zv db 5432
Connection to db (172.28.0.3) 5432 port [tcp/*] succeeded!

The DB is reachable by its service name db, but not on 127.0.0.1.

Acceptance

You've solved it when:

  • You've shown the app's connection target 127.0.0.1:5432 is refused from
INSIDE the app container (docker exec app nc -zv 127.0.0.1 5432) while the DB IS reachable by its service name (docker exec app nc -zv db 5432 succeeds). Inside the app's network namespace, 127.0.0.1 is the app's own loopback — Postgres lives in the db container's separate netns, so nothing answers on the app's localhost:5432. NOT misdiagnosed as the DB being down, a crashed Postgres, or a wrong port (docker ps shows db Up; db answers on 5432 by name).
  • You've stated the fix: point the app's DB connection string at the service
name db (e.g. DATABASE_URL=…@db:5432/…) instead of localhost/127.0.0.1, and recreate the app.

Constraints

  • Tools: docker CLI only.
  • docker restart app does NOT help — the 127.0.0.1 host is in the app's
config and survives a restart.
  • The DB is not down and the port is not wrong; db answers on 5432 by name.
Don't chase a Postgres crash, a port change, or publishing 5432 to the host.

Follow-up

  1. Why does 127.0.0.1 mean something different inside the app container than
it does on your laptop or inside the db container?
  1. How does the app resolve the name db to an IP at all — what serves that
DNS answer, and what would break it (hint: the shared user network)?
  1. Why is binding Postgres to 0.0.0.0 necessary-but-not-sufficient here, and
why would publishing -p 5432:5432 be the wrong fix for app↔db traffic?
Live session
Code
SavedNo commands yet