Docker Nginx PHP-FPM Error: How to Fix “host not found in upstream” in Containerized Environments


4 views

When deploying a LEMP stack with Docker containers, you might encounter the frustrating error:

[emerg] 1#1: host not found in upstream "php-fpm:9000" in /etc/nginx/conf.d/upstream.conf:1

This typically occurs when Nginx can't resolve the PHP-FPM container's hostname. While the setup works locally, production deployments often fail due to differences in container networking.

The key difference lies in how Docker handles container networking between environments:

# Local development (working)
docker-compose up -d
# Containers can resolve each other's names automatically

# Production (failing)
docker run -d nginx
docker run -d php-fpm
# Containers can't discover each other without explicit networking

Solution 1: Using Docker Compose with Explicit Links

For development/production parity, use this docker-compose.yml:

version: '3'
services:
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    depends_on:
      - php
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    links:
      - php:php-fpm

  php:
    image: php:7.4-fpm
    volumes:
      - ./code:/var/www/html

Solution 2: Custom Network Configuration

For standalone Docker deployments:

# Create a custom network
docker network create lemp_network

# Run PHP-FPM container
docker run -d --name php-fpm --network lemp_network php:7.4-fpm

# Run Nginx container
docker run -d --name nginx --network lemp_network -p 80:80 nginx

Solution 3: Environment Variables in Production

Modify your Nginx Dockerfile to handle dynamic upstreams:

FROM nginx:latest

# Use environment variables with defaults
RUN echo "upstream php-upstream { server ${PHP_FPM_HOST:-php-fpm}:${PHP_FPM_PORT:-9000}; }" > /etc/nginx/conf.d/upstream.conf

CMD ["nginx", "-g", "daemon off;"]

Then run with:

docker run -d -e PHP_FPM_HOST=your_php_container_name nginx

If you're still facing issues:

# Check container networking
docker network inspect bridge

# Test DNS resolution from within Nginx container
docker exec -it nginx_container ping php-fpm

# Verify container links
docker inspect nginx_container | grep Links

For production environments, consider:

  • Using Docker Swarm or Kubernetes with proper service discovery
  • Implementing health checks in your containers
  • Setting up proper restart policies

Here's a robust production-grade docker-compose.yml snippet:

services:
  nginx:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3
    deploy:
      restart_policy:
        condition: on-failure
        
  php:
    healthcheck:
      test: ["CMD-SHELL", "php -v"]
      interval: 30s

When deploying a LEMP stack with Docker containers, you might encounter this frustrating error in your Nginx logs:

[emerg] 1#1: host not found in upstream "php-fpm:9000" in /etc/nginx/conf.d/upstream.conf:1

The error occurs when Nginx can't resolve the hostname of your PHP-FPM container, typically during container startup.

The key difference between local and production environments often comes down to:

  • Different Docker networking configurations
  • Missing or misconfigured container dependencies
  • Environment variables not being properly passed
  • DNS resolution timing issues during container startup

Here are several approaches that have worked for developers:

1. Using Docker's Internal DNS

Modify your Nginx configuration to use Docker's internal networking:

upstream php-upstream {
  server php-fpm:9000;
}

And ensure your docker-compose.yml has:

version: '3'
services:
  nginx:
    depends_on:
      - php-fpm
    networks:
      - app-network
  
  php-fpm:
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

2. Custom Network Solution

Create a custom network and explicitly name your services:

docker network create lemp-network

Then in docker-compose.yml:

services:
  nginx:
    networks:
      lemp-network:
        aliases:
          - nginx-service
  
  php-fpm:
    networks:
      lemp-network:
        aliases:
          - php-fpm-service

3. Startup Order Control

Add a health check and wait-for script:

healthcheck:
  test: ["CMD", "nc", "-z", "php-fpm", "9000"]
  interval: 5s
  timeout: 5s
  retries: 5

For production environments, consider these additional measures:

# In your Nginx Dockerfile
RUN echo "resolver 127.0.0.11 valid=30s;" >> /etc/nginx/nginx.conf

This configures Nginx to use Docker's embedded DNS server with proper caching settings.

After implementing any solution, verify with:

docker exec -it nginx-container cat /etc/nginx/conf.d/upstream.conf
docker exec -it nginx-container nslookup php-fpm