diff --git a/docker-compose.yml b/docker-compose.yml index 82c5deee853..1a6762c33f6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -601,11 +601,19 @@ services: ports: - "$SENTRY_BIND:80/tcp" image: "nginx:1.31.4-alpine" + environment: + # nginx.conf needs the container engine's DNS address, which differs per engine. + # The image reads it from /etc/resolv.conf into NGINX_LOCAL_RESOLVERS and substitutes + # it into templates, so nginx.conf is mounted as one and rendered over the image default. + # The filter keeps envsubst away from the nginx runtime variables in the config. + NGINX_ENTRYPOINT_LOCAL_RESOLVERS: 1 + NGINX_ENVSUBST_OUTPUT_DIR: /etc/nginx + NGINX_ENVSUBST_FILTER: "^NGINX_LOCAL_RESOLVERS$$" volumes: - type: bind read_only: true source: ./nginx.conf - target: /etc/nginx/nginx.conf + target: /etc/nginx/templates/nginx.conf.template - sentry-nginx-cache:/var/cache/nginx - sentry-nginx-www:/var/www healthcheck: diff --git a/nginx.conf b/nginx.conf index f15cb8cb51c..3aa2c10049f 100644 --- a/nginx.conf +++ b/nginx.conf @@ -65,13 +65,27 @@ http { proxy_read_timeout 90s; proxy_send_timeout 5s; + # Without "resolve", nginx looks the service names up once at startup and keeps that address + # for the life of the worker process. Docker does not guarantee a container the same address + # across starts, so nginx can end up proxying to a container that no longer owns it and + # answer every request with 502 until someone restarts nginx by hand. + # "resolve" needs a resolver, and the container engine's own DNS is the only thing on a Compose + # network that knows the service names. Its address differs per engine -- 127.0.0.11 on Docker, + # the network gateway on Podman -- so it is read from /etc/resolv.conf at startup by + # /docker-entrypoint.d/15-local-resolvers.envsh, which is why this file is a template. + # There are no AAAA records worth waiting for on a Compose network. + resolver ${NGINX_LOCAL_RESOLVERS} valid=10s ipv6=off; + upstream relay { - server relay:3000; + # "resolve" requires the upstream group in shared memory, hence "zone". + zone relay 64k; + server relay:3000 resolve; keepalive 2; } upstream sentry { - server web:9000; + zone sentry 64k; + server web:9000 resolve; keepalive 2; }