Troubleshooting Docker Compose: 'server not found' Container Name Resolution Errors

Resolve inter-container communication failures in Docker Compose due to DNS issues. Diagnose 'server not found' errors when containers can't locate each other.


When deploying multi-service applications with Docker Compose, inter-container communication relies heavily on Docker’s built-in DNS resolution. An error indicating “server not found” or “name or service not known” signals a critical failure in this name resolution process, preventing containers from locating and communicating with their dependencies. This guide will walk you through diagnosing and resolving such issues within your Docker Compose stack.

Symptom & Error Signature

The primary symptom is a service within your Docker Compose stack failing to connect to another service, typically presenting as a DNS resolution error. This can manifest in application logs, curl commands executed from within a container, or ping attempts.

# Example from inside a container attempting to reach another service
$ docker exec -it myapp_web_1 bash
root@<container_id>:/app# curl http://myservice_db:5432
curl: (6) Could not resolve host: myservice_db

# Example from application logs (e.g., Node.js, PHP, Python)
web_1    | 2026-07-04 10:30:05.123Z ERROR: Unable to connect to database.
web_1    | Error: getaddrinfo ENOTFOUND myservice_db
# or
web_1    | PHP Fatal error: Uncaught PDOException: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo for myservice_db failed: Name or service not known

# Example from a container trying to ping another
$ docker exec -it myapp_web_1 bash
root@<container_id>:/app# ping myservice_backend
ping: myservice_backend: Name or service not known

The key indicator is Could not resolve host, ENOTFOUND, Name or service not known, or similar messages explicitly mentioning a failure to resolve the hostname of an internal Docker service.

Root Cause Analysis

The “server not found” error for inter-container communication in Docker Compose primarily stems from issues with Docker’s internal DNS resolution mechanism. Here are the most common underlying reasons:

  1. Incorrect Service Naming or Typo: The most frequent cause. The hostname used to reference a target container must precisely match its service name as defined in your docker-compose.yml file. Docker’s internal DNS service registers each service name as an alias for its containers’ IP addresses within the Compose network.
  2. Target Service Not Running or Healthy: If the target service (e.g., myservice_db) is not running, has crashed, or is stuck in an unhealthy state, Docker’s internal DNS may not have a valid IP address to resolve for that service name.
  3. Docker Compose Network Misconfiguration:
    • Services in Different Networks: If services are explicitly defined in different custom networks and not connected, they cannot resolve each other’s hostnames. By default, all services in a docker-compose.yml are connected to a single, implicitly created network (<projectname>_default).
    • Incorrect network_mode: Using network_mode: "host" or network_mode: "service:..." can bypass Docker’s internal DNS, requiring direct IP addresses or host-level DNS, which is generally not suitable for inter-container resolution by service name.
    • External Networks: Misconfiguration when attempting to connect to pre-existing external networks.
  4. Docker Daemon DNS Resolver Issues: Less common for inter-container resolution, but possible if the Docker daemon’s global DNS configuration (e.g., in /etc/docker/daemon.json) is incorrect or points to an unreachable DNS server, potentially affecting how Docker itself resolves names, including internal ones or external names requested by containers.
  5. Host Firewall Interference: While Docker typically manages its own iptables rules, an aggressively configured host firewall (like ufw on Ubuntu) could, in rare scenarios, interfere with traffic on Docker’s bridge networks, preventing internal DNS queries or responses.
  6. Stale Docker State: Occasionally, Docker’s internal state, including network and DNS configurations, can become corrupted or stale, requiring a clean rebuild of the stack.

Step-by-Step Resolution

Follow these steps meticulously to diagnose and resolve the “server not found” issue.

1. Verify Service Naming Convention and docker-compose.yml Consistency

The service name defined in docker-compose.yml acts as the hostname for other services within the same Docker Compose network. Ensure that the hostname used in your application code or environment variables precisely matches the service name.

  1. Inspect your docker-compose.yml: Locate the service that is failing to connect and the service it’s trying to reach. Note their exact service names.

    # Example docker-compose.yml
    version: '3.8'
    services:
      web:
        build: ./web_app
        ports:
          - "80:80"
        environment:
          DATABASE_HOST: db_service # This must match the 'db_service' below
          DATABASE_PORT: 5432
      db_service: # This is the service name acting as the hostname
        image: postgres:13
        environment:
          POSTGRES_DB: mydatabase
          POSTGRES_USER: user
          POSTGRES_PASSWORD: password
        volumes:
          - db_data:/var/lib/postgresql/data
    volumes:
      db_data:
  2. Check Application Code/Environment Variables: Confirm that the hostname referenced within the web service’s application code or its environment variables (DATABASE_HOST in the example) exactly matches db_service. A common mistake is using localhost, the container image name (e.g., postgres), or a custom alias that isn’t defined.

2. Confirm All Dependent Services Are Running and Healthy

A service cannot be resolved if it’s not running or has crashed.

  1. List running services: Use docker-compose ps to see the status of all services in your stack.

    $ docker-compose ps
    NAME                COMMAND                  SERVICE         STATUS              PORTS
    myapp-web-1         "/docker-entrypoint.…"   web             running             0.0.0.0:80->80/tcp
    myapp-db_service-1  "docker-entrypoint.s…"   db_service      running             5432/tcp

    Ensure the STATUS column for the target service (e.g., db_service) shows running or healthy. If it shows Exited or restarting, you need to debug that service’s startup failure first.

  2. Review logs of the target service: Check the logs of the service that couldn’t be found for any startup errors.

    $ docker-compose logs db_service

    Look for errors indicating why the service might not be fully operational or has exited prematurely.

3. Inspect Docker Compose Network Configuration

Docker Compose automatically creates a default network for all services. If you’re using custom networks, ensure they are correctly configured and services are attached to them.

  1. Check implicit network: If no networks section is defined in docker-compose.yml, all services are connected to a single default bridge network named <projectname>_default (e.g., myapp_default). Services on this network should be able to resolve each other by name.

  2. Review explicit network definitions: If you have a networks section, ensure that both the failing and the target service are explicitly assigned to the same network.

    # Example with explicit networks
    version: '3.8'
    services:
      web:
        build: ./web_app
        networks:
          - my_app_network # Connected to this network
      db_service:
        image: postgres:13
        networks:
          - my_app_network # Also connected to this network
    networks:
      my_app_network: # Definition of the custom network
        driver: bridge

    If services are on different networks, they will not be able to resolve each other’s hostnames without additional linking or external network configuration, which is generally not recommended for simple inter-service communication.

  3. Inspect running container networks: You can verify which networks a container is connected to using docker inspect.

    $ docker inspect myapp-web-1 | grep -A 5 "Networks"

    Confirm that both containers share at least one common network.

4. Manually Test Name Resolution within a Container

This is a crucial diagnostic step to confirm if the DNS resolution issue is internal to the container or a broader Docker problem.

  1. Access the failing container’s shell:

    $ docker exec -it myapp-web-1 sh # or bash, depending on the container image
  2. Install DNS utilities (if needed): Some minimal container images might not have ping, nslookup, or dig installed.

    # For Debian/Ubuntu-based images
    apt update && apt install -y iputils-ping dnsutils
    # For Alpine-based images
    apk add --no-cache iputils busybox-extras
  3. Attempt to ping the target service:

    # From inside the web container, ping the db_service
    root@<web_container_id>:/app# ping -c 3 db_service

    If ping fails with “Name or service not known”, it confirms the DNS resolution issue. If it resolves to an IP but still can’t connect, you might have a different issue (e.g., port or firewall).

  4. Use nslookup or dig: These tools provide more detail about DNS resolution.

    root@<web_container_id>:/app# nslookup db_service
    # Expected successful output:
    # Server:         127.0.0.11
    # Address:        127.0.0.11#53
    #
    # Name:   db_service
    # Address: 172.18.0.2  # This IP will vary

    If nslookup returns can't resolve 'db_service': Name or service not known, the problem is definitively with DNS resolution. The Server: 127.0.0.11 indicates Docker’s internal DNS resolver.

5. Review Docker Daemon DNS Configuration (Advanced)

While Docker’s internal DNS for docker-compose is largely self-contained, an incorrect global Docker daemon DNS setting can sometimes interfere.

  1. Check /etc/docker/daemon.json: This file configures the Docker daemon. Look for a dns key.

    $ cat /etc/docker/daemon.json

    If you see something like:

    {
      "dns": ["8.8.8.8", "8.8.4.4"]
    }

    and these DNS servers are unreachable or misconfigured, it might indirectly affect Docker’s internal DNS if it tries to forward queries (though less common for inter-container resolution).

    [!WARNING] Do not add public DNS servers (e.g., 8.8.8.8) to daemon.json unless absolutely necessary and you understand the implications. Docker’s default internal DNS is highly optimized for inter-container communication. Adding external DNS can sometimes introduce more problems than it solves for this specific issue.

  2. Remove or correct dns entries: If you have dns entries that are suspect, temporarily remove them or change them to reliable, local DNS servers (if required by your network).

  3. Restart Docker daemon: After modifying daemon.json, the Docker daemon must be restarted.

    $ sudo systemctl restart docker

6. Check Host Firewall (UFW) Rules

On Ubuntu, ufw (Uncomplicated Firewall) is commonly used. Docker automatically manages iptables rules for its networks, but ufw can sometimes interfere.

  1. Check UFW status:

    $ sudo ufw status

    Look for rules that might be explicitly blocking traffic on Docker’s bridge interfaces (e.g., docker0, or custom bridge interfaces like br-XXXXXXXXXXXX). By default, ufw should not block internal Docker traffic if ufw is configured to allow Docker’s iptables rules.

  2. Temporarily disable UFW (for testing):

    [!WARNING] Disabling your host firewall can expose your system to security risks. Only do this temporarily for testing in a controlled environment and re-enable it immediately after.

    $ sudo ufw disable

    After disabling, re-test your Docker Compose stack. If the issue resolves, you’ll need to configure ufw to properly coexist with Docker. A common solution is to ensure the /etc/default/ufw file has DEFAULT_FORWARD_POLICY="ACCEPT" or to use specific ufw rules to allow Docker traffic, though Docker’s iptables management usually takes precedence.

7. Perform a Clean Stack Rebuild

If all previous steps fail, a clean rebuild of your Docker Compose stack can resolve issues caused by stale or corrupted Docker internal states, including networks and DNS caches.

  1. Stop and remove the entire stack: The --volumes flag removes any named volumes, and --remove-orphans removes containers not defined in the current docker-compose.yml.

    [!IMPORTANT] Using --volumes will delete all data stored in named volumes. If you have critical data in volumes (e.g., a database), ensure you have backups or omit --volumes and only remove networks.

    $ docker-compose down --volumes --remove-orphans

    If you want to preserve data volumes but ensure networks are completely clean:

    $ docker-compose down --remove-orphans
    $ docker network ls -q --filter "label=com.docker.compose.project=<your_project_name>" | xargs -r docker network rm

    Replace <your_project_name> with the name of your Docker Compose project (usually the directory name containing docker-compose.yml).

  2. Bring the stack up again with a fresh build: The --build flag ensures that container images are rebuilt, which is useful if there were changes in your Dockerfiles.

    $ docker-compose up -d --build

After performing these steps, your Docker Compose services should be able to resolve each other’s hostnames correctly, restoring inter-container communication.