Docker Compose部署多容器Django应用时Nginx上游主机未找到报错求助
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 webto 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 psto confirm its status showsUp.
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
webinweb:8000must match the service name indocker-compose.ymlexactly. - 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
portsconfig in docker-compose). - Make sure your Django app is listening on
0.0.0.0instead of127.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:
- Create a file named
wait-for-it.shin yournginxdirectory 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 - Update your
nginx/Dockerfileto 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 lsto 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 thewebandnginxcontainers are listed underContainers, and thewebcontainer has the aliasweb.
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

