You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker Compose部署多容器Django应用时Nginx上游主机未找到报错求助

Troubleshooting "Host not found in upstream 'web'" Error in Docker Compose Django App

Hey there! Let's work through this Nginx upstream error together—it's one of the most common hiccups when setting up multi-container Django apps, so you're not alone here. Let's break down the possible causes step by step:

1. Double-Check Your Docker Compose Service Name

First off, Nginx is trying to connect to a service named web, so make sure your docker-compose.yml actually has a service with that exact name (Docker Compose service names are case-sensitive!).

Open your docker-compose.yml and verify the services section looks something like this:

services:
  web:
    build: .
    # Your other web service configs (volumes, environment variables, etc.)
  nginx:
    build: ./nginx
    # Nginx configs...

If your Django service is named something else (like django instead of web), you'll need to either rename it to web or update the upstream line in your Nginx config to match the correct service name.

2. Verify the Web Container Actually Starts

Sometimes the error happens because the web container fails to start at all, so Nginx has nothing to connect to. Let's test this:

  • Run docker-compose up web to start only the web service. Watch the logs—if there are any errors (like missing dependencies, database connection issues, etc.), fix those first.
  • Once the web service is running without errors, run docker-compose ps to confirm its status shows Up.

3. Check Your Nginx Upstream Configuration

Head to your nginx/sites-enabled/django_project file and look at line 12 (the one throwing the error). It should look like this:

upstream web {
    server web:8000; # Replace 8000 with the port your Django app uses INSIDE the container
}

A few critical things to note here:

  • The web in web:8000 must match the service name in docker-compose.yml exactly.
  • The port number (8000 here) is the port your Django app is listening on inside the web container—not the port you've mapped to your host machine (that's the left side of the ports config in docker-compose).
  • Make sure your Django app is listening on 0.0.0.0 instead of 127.0.0.1! If it's only listening locally inside the container, Nginx won't be able to reach it. For example, if you're using Gunicorn, your start command should be:
    gunicorn myproject.wsgi:application --bind 0.0.0.0:8000
    

4. Fix the Container Startup Order

Docker Compose's depends_on only ensures containers start in order—it doesn't wait for the service inside the container to be fully ready. That means Nginx might start before your Django app is up and running, leading to the "host not found" error.

Option 1: Use Health Checks

Add a health check to your web service in docker-compose.yml so Docker knows when it's ready, then have Nginx wait for that:

services:
  web:
    build: .
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/"] # Adjust this to a dedicated health endpoint if you have one
      interval: 10s
      timeout: 5s
      retries: 5
  nginx:
    build: ./nginx
    depends_on:
      web:
        condition: service_healthy

Option 2: Use a Wait Script

If you don't want to use health checks, you can add a simple wait script to your Nginx container to ensure it only starts once the web service is reachable:

  1. Create a file named wait-for-it.sh in your nginx directory with the following content:
    #!/usr/bin/env bash
    # Use this script to test if a given TCP host/port are available
    
    WAITFORIT_cmdname=${0##*/}
    
    echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
    
    usage()
    {
        cat << USAGE >&2
    Usage:
        $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
        -h HOST | --host=HOST       Host or IP under test
        -p PORT | --port=PORT       TCP port under test
                                    Alternatively, you specify the host and port as host:port
        -s | --strict               Only execute subcommand if the test succeeds
        -q | --quiet                Don't output any status messages
        -t TIMEOUT | --timeout=TIMEOUT
                                    Timeout in seconds, zero for no timeout
        -- COMMAND ARGS             Execute command with args after the test finishes
    USAGE
        exit 1
    }
    
    wait_for()
    {
        if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
            echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
        else
            echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
        fi
        WAITFORIT_start_ts=$(date +%s)
        while :
        do
            if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
                nc -z $WAITFORIT_HOST $WAITFORIT_PORT
                WAITFORIT_result=$?
            else
                (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
                WAITFORIT_result=$?
            fi
            if [[ $WAITFORIT_result -eq 0 ]]; then
                WAITFORIT_end_ts=$(date +%s)
                echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
                break
            fi
            sleep 1
        done
        return $WAITFORIT_result
    }
    
    wait_for_wrapper()
    {
        # In order to support SIGINT during timeout
        if [[ $WAITFORIT_QUIET -eq 1 ]]; then
            timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
        else
            timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
        fi
        WAITFORIT_PID=$!
        trap "kill -INT -$WAITFORIT_PID" INT
        wait $WAITFORIT_PID
        WAITFORIT_RESULT=$?
        if [[ $WAITFORIT_RESULT -ne 0 ]]; then
            echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
        fi
        return $WAITFORIT_RESULT
    }
    
    # process arguments
    while [[ $# -gt 0 ]]
    do
        case "$1" in
            *:* )
            WAITFORIT_hostport=(${1//:/ })
            WAITFORIT_HOST=${WAITFORIT_hostport[0]}
            WAITFORIT_PORT=${WAITFORIT_hostport[1]}
            shift 1
            ;;
            --child)
            WAITFORIT_CHILD=1
            shift 1
            ;;
            -q | --quiet)
            WAITFORIT_QUIET=1
            shift 1
            ;;
            -s | --strict)
            WAITFORIT_STRICT=1
            shift 1
            ;;
            -h)
            WAITFORIT_HOST="$2"
            if [[ $WAITFORIT_HOST == "" ]]; then break; fi
            shift 2
            ;;
            --host=*)
            WAITFORIT_HOST="${1#*=}"
            shift 1
            ;;
            -p)
            WAITFORIT_PORT="$2"
            if [[ $WAITFORIT_PORT == "" ]]; then break; fi
            shift 2
            ;;
            --port=*)
            WAITFORIT_PORT="${1#*=}"
            shift 1
            ;;
            -t)
            WAITFORIT_TIMEOUT="$2"
            if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
            shift 2
            ;;
            --timeout=*)
            WAITFORIT_TIMEOUT="${1#*=}"
            shift 1
            ;;
            --)
            shift
            WAITFORIT_CLI=("$@")
            break
            ;;
            --help)
            usage
            ;;
            *)
            echoerr "Unknown argument: $1"
            usage
            ;;
        esac
    done
    
    if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
        echoerr "Error: you need to provide a host and port to test."
        usage
    fi
    
    WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
    WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
    WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
    WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
    
    # Check to see if timeout is from busybox?
    WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
    WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
    if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
            WAITFORIT_ISBUSY=1
            WAITFORIT_BUSYTIMEFLAG="-t"
    
    else
            WAITFORIT_ISBUSY=0
            WAITFORIT_BUSYTIMEFLAG=""
    fi
    
    if [[ $WAITFORIT_CHILD -gt 0 ]]; then
        wait_for
        WAITFORIT_RESULT=$?
        exit $WAITFORIT_RESULT
    else
        if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
            wait_for_wrapper
            WAITFORIT_RESULT=$?
        else
            wait_for
            WAITFORIT_RESULT=$?
        fi
    fi
    
    if [[ $WAITFORIT_CLI != "" ]]; then
        if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
            echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
            exit $WAITFORIT_RESULT
        fi
        exec "${WAITFORIT_CLI[@]}"
    else
        exit $WAITFORIT_RESULT
    fi
    
  2. Update your nginx/Dockerfile to install necessary dependencies and use the script to start Nginx:
    FROM nginx:alpine
    RUN apk add --no-cache bash curl netcat-openbsd
    COPY wait-for-it.sh /usr/local/bin/
    RUN chmod +x /usr/local/bin/wait-for-it.sh
    COPY sites-enabled/django_project /etc/nginx/sites-enabled/
    CMD ["wait-for-it.sh", "web:8000", "--", "nginx", "-g", "daemon off;"]
    

5. Verify Docker Network Setup

Docker Compose automatically creates a shared network for all your services, so they should be able to communicate via service names. To confirm:

  • Run docker network ls to find your project's network (it'll be named something like <your_project_folder>_default).
  • Run docker network inspect <network_name> and check that both the web and nginx containers are listed under Containers, and the web container has the alias web.

If you work through these steps, you should be able to track down the issue. Let me know if you hit any snags along the way!

内容的提问来源于stack exchange,提问作者TJB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:27:11