Fix 'dial tcp: lookup db on 127.0.0.1:53: no such host' in Docker Compose

intermediate๐Ÿณ Docker2026-04-22| Docker 20.10+, Docker Compose v2, Linux/macOS/Windows WSL2

Error Message

dial tcp: lookup db on 127.0.0.1:53: no such host
#docker-compose#networking#dns#localhost

The situation

It's 2 AM and your app container is throwing this every few seconds:

dial tcp: lookup db on 127.0.0.1:53: no such host

Your docker-compose.yml has a service named db. Your app is clearly trying to reach it. The DB container is running โ€” you checked. So what's going on?

The short answer: your app container is using 127.0.0.1:53 as its DNS server. That's the host machine's loopback resolver โ€” not Docker's internal DNS. Docker's service name resolution runs through its own embedded DNS at 127.0.0.11. The host resolver has never heard of db, so it fails immediately.

This happens when a container isn't on a Docker-managed network, or when something broke its DNS config. Either way, it falls back to the system resolver โ€” and the system has no idea what db means.

Debug process

Step 1: Check if both containers are on the same network

Nine times out of ten, this is the problem. Run:

docker network ls
docker inspect <your_container_name> | grep -A 20 '"Networks"'

Look at the Networks section. App container on bridge (the default legacy network) but DB on myapp_default? They're isolated from each other โ€” service names won't resolve across different networks.

Step 2: Verify Docker's internal DNS is being used

Exec into the app container and check:

docker exec -it <app_container> cat /etc/resolv.conf

A healthy Docker container should show:

nameserver 127.0.0.11
options ndots:0

Seeing nameserver 127.0.0.1 or a public resolver like 8.8.8.8? Docker's DNS isn't wired up. This happens when containers run with --network host, or when they're not attached to a user-defined network.

Step 3: Test name resolution manually

docker exec -it <app_container> nslookup db
docker exec -it <app_container> ping db

nslookup fails but the DB container is running? Network attachment problem. Not an app config problem.

Solutions

Solution 1: Put both services on the same named network (Docker Compose)

Start here โ€” this resolves 90% of cases. In your docker-compose.yml:

services:
  app:
    build: .
    networks:
      - backend
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/mydb

  db:
    image: postgres:15
    networks:
      - backend

networks:
  backend:
    driver: bridge

When both services live in the same Compose file without explicit network config, Docker Compose automatically creates a shared network named <project>_default and puts everything on it. Service names resolve automatically. No extra config needed.

The error creeps in when:

  • You override networks: on one service but forget the other
  • One container was started manually with docker run instead of through Compose
  • You have multiple Compose files with services on different project networks

Solution 2: Connect a manually-run container to the Compose network

Started your app with docker run while the DB lives in a Compose stack? Connect them:

# Find the network name
docker network ls

# Connect your standalone container
docker network connect myproject_default <app_container_name>

No restart needed. Service name resolution kicks in immediately after connecting.

Solution 3: Drop --network host

--network host makes a container share the host's network stack entirely. Docker's internal DNS doesn't apply. Service names won't resolve โ€” full stop.

Unless you actually need host networking (raw sockets, hardware access, very specific port binding scenarios), remove it:

# Wrong
docker run --network host myapp

# Right โ€” use a named network
docker run --network myproject_default myapp

Solution 4: Multiple Compose files โ€” create a shared external network

Running separate Compose stacks that need to talk? Define one shared network explicitly:

# In your DB stack (docker-compose.db.yml)
networks:
  shared:
    name: shared_backend
    driver: bridge
# In your app stack (docker-compose.app.yml)
networks:
  shared:
    external: true
    name: shared_backend

Both stacks now share the same network. Service names resolve across stacks without any extra tricks.

Verification

Run these checks to confirm the fix took effect:

# Check container is on the right network
docker inspect <app_container> | grep -A 5 '"Networks"'

# Confirm Docker DNS is active
docker exec -it <app_container> cat /etc/resolv.conf
# Should show: nameserver 127.0.0.11

# Test name resolution
docker exec -it <app_container> nslookup db
# Should resolve to an internal IP like 172.18.0.x

nslookup db returns an IP? You're good. Still seeing errors in the app? Restart the app container โ€” some runtimes (notably Go and Java apps) cache DNS failures in memory and won't retry until the process restarts.

Tip: Debugging subnet conflicts

DNS resolved but connections still fail? Check for subnet collisions. Docker picks CIDR ranges automatically โ€” sometimes they overlap with your VPN or office network and break routing entirely. Check your network's subnet:

docker network inspect <network_name> | grep Subnet

A common culprit: Docker defaulting to 172.17.0.0/16 while your VPN uses the same range. Pin a custom subnet in your Compose file to avoid the conflict:

networks:
  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 10.50.0.0/24

When sorting out which addresses fall in which subnet, I reach for the Subnet Calculator on ToolCraft โ€” browser-based, shows the broadcast address, usable range, and wildcard mask without phoning home.

Lessons learned

  • Service name DNS only works on user-defined networks. The default bridge network doesn't support service discovery. Name your networks in Compose โ€” always.
  • Mixing docker run and docker compose causes this silently. A container started by hand won't automatically join a Compose network. You have to connect it manually with docker network connect.
  • --network host is a sledgehammer. It bypasses Docker DNS entirely. Reach for it only when you genuinely need it, not as a quick fix for port binding issues.
  • The nameserver line in /etc/resolv.conf tells you everything. 127.0.0.11 means Docker DNS is active and service names will work. Anything else means you're resolving outside Docker โ€” and db is meaningless out there.

Related Error Notes