Docker Compose Networking: Solving nginx 'host not found in upstream' Error

Nov 23, 2025 · Programming · 11 views · 7.8

Keywords: Docker Compose | Container Startup Order | nginx upstream | depends_on | Service Dependencies

Abstract: This technical paper examines the nginx upstream host resolution issue during migration to Docker Compose's new networking features. It provides an in-depth analysis of container startup order dependencies and presents the depends_on directive as the primary solution, with comparisons to alternative approaches like volumes_from. The paper includes comprehensive configuration examples and implementation guidelines.

Problem Context and Symptom Analysis

When migrating from traditional link mechanisms to Docker 1.9 and Docker-Compose 1.5's new networking features, developers frequently encounter nginx container startup failures. The specific manifestation is nginx exiting immediately upon first startup with the error [emerg] host not found in upstream "waapi_php_1". The root cause lies in the uncontrollable nature of container startup order: the nginx container begins hostname resolution before the php-fpm service has fully started and registered with Docker's internal DNS.

Core Issue: Container Startup Order Dependencies

Docker Compose's default behavior is to start all service containers in parallel, which works well for stateless services but creates problems for services with explicit dependencies (such as nginx depending on php-fpm). When nginx configuration uses fastcgi_pass waapi_php_1:9000;, Docker's internal DNS must be able to resolve the waapi_php_1 hostname when nginx starts. If the php-fpm container hasn't fully started, DNS queries will fail, causing nginx configuration validation errors.

Primary Solution: The depends_on Directive

Docker Compose file format version 2 introduced the depends_on directive specifically to address service startup order dependencies. By explicitly declaring service dependencies in docker-compose.yml, you can ensure that dependent services don't start running before their required services.

version: '2'
services:
  nginx:
    image: nginx
    ports:
      - "42080:80"
    volumes:
      - ./config/docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - php

  php:
    build: config/docker/php
    ports:
      - "42022:22"
    volumes:
      - .:/var/www/html
    env_file: config/docker/php/.env.development
    depends_on:
      - mongo

  mongo:
    image: mongo
    ports:
      - "42017:27017"
    volumes:
      - /var/mongodata/wa-api:/data/db
    command: --smallfiles

In this configuration, depends_on ensures the startup sequence: mongo → php → nginx. When executing docker-compose up, Docker Compose first starts the mongo container, waits for it to be ready, then starts the php container, and finally starts the nginx container. This sequence guarantees that when nginx attempts to resolve waapi_php_1, the php-fpm service has already registered with Docker's network DNS.

Alternative Approaches Comparison and Analysis

volumes_from Workaround

Before the depends_on feature was fully implemented, developers used volumes_from as a temporary solution:

nginx:
  image: nginx
  ports:
    - "42080:80"
  volumes:
    - ./config/docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
  volumes_from:
    - php

This approach implicitly creates container dependencies through volume sharing, as Docker ensures that dependent containers (php) start before the containers that depend on them (nginx). However, this method has significant drawbacks: all volumes of the php container are exposed to the nginx container, potentially causing unnecessary security risks and resource leaks. This approach should be avoided in formal production environments.

nginx Retry Mechanism

Another solution involves implementing health checks and retry mechanisms for upstream services in the nginx configuration:

upstream phpupstream {
   server waapi_php_1:9000 fail_timeout=5s max_fails=5;
}

location ~ ^/.+\.php(/|$) {
    fastcgi_pass phpupstream;
    # other fastcgi configurations...

By setting max_fails and fail_timeout parameters, nginx will attempt to connect to the upstream service multiple times within the specified period, until the service becomes available or the maximum retry count is reached. This method shifts the fault tolerance responsibility to the application layer and is suitable for scenarios where strict startup timing is not required.

Service Naming and Configuration Consistency

Ensuring consistency between service names in the Docker Compose file and nginx configuration is crucial. If the php service is named php_service in docker-compose.yml, then the same hostname must be used in the nginx configuration:

fastcgi_pass php_service:9000;

Docker Compose creates corresponding hostnames for each service, which are resolvable within the container network. Incorrect hostname references are a common cause of "host not found" errors.

Best Practice Recommendations

Based on the above analysis, the following best practices are recommended:

  1. Use Docker Compose File Version 2: Ensure docker-compose.yml starts with version: '2' to support modern features like depends_on.
  2. Explicitly Declare All Dependencies: List all direct and indirect dependent services in depends_on.
  3. Combine with Health Checks: While depends_on controls startup order, it's recommended to add health checks for critical services to ensure services are truly available, not just that containers are running.
  4. Avoid Over-Dependency: Use startup order control only when necessary, as overuse can reduce the parallelism and resilience of container orchestration.

Conclusion

Docker Compose's depends_on directive provides an elegant solution for handling container startup order dependencies. Compared to traditional volumes_from workarounds, it is safer, more explicit, and better aligned with container orchestration best practices. Through proper configuration of service dependencies and nginx retry mechanisms, stable and reliable Dockerized application architectures can be constructed.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.