nginx-proxy upgrade: jwilder → nginxproxy/nginx-proxy
When this applies
jwilder/nginx-proxy (last released ~2021) does not support the
com.github.nginx-proxy.nginx-proxy.network container label. When a backend
container is attached to two Docker networks that nginx-proxy is also on,
the old image registers two upstream server entries for the same container —
causing round-robin to alternate between the container’s two IPs (same process,
wrong abstraction). Symptoms: API calls succeed roughly 50 % of the time;
intermittent 502/503 or wrong-network timeouts.
Confirm the symptom
# On bms-1 as root
docker exec nginx-proxy grep -A20 'upstream api.w4.pinbox24.com' \
/etc/nginx/conf.d/default.conf
# BAD: two `server` lines for the same container
# GOOD: one `server` line + comment "(ignored; reachable but redundant)"Rollback image (before any change)
docker tag jwilder/nginx-proxy jwilder/nginx-proxy:pre-upgrade-$(date +%Y%m%d)
# Verify the tag exists
docker images jwilder/nginx-proxyAdd label to backend container
In the backend’s docker-compose.yml (e.g. pinbox24/p24-back-ts):
services:
backend:
labels:
- "com.github.nginx-proxy.nginx-proxy.network=test-net"
networks:
- prod-v-4-net
- test-netCommit this to the GitLab repo before the swap — the label is meaningless on the old image but harmless, and it will be live on the new image immediately.
Swap nginx-proxy image (live, ~10 s downtime)
nginx-proxy on bms-1 is NOT managed by docker-compose. All config is in bind
mounts under /docker/vol/etc/nginx/; no data loss on container swap.
# 1. Pull new image
docker pull nginxproxy/nginx-proxy:latest
# 2. Stop old container; rename so the name is free
docker stop nginx-proxy
docker rename nginx-proxy nginx-proxy-old-jwilder
# 3. Start new container with same volumes/ports
DHPARAM_VOL=$(docker inspect nginx-proxy-old-jwilder \
--format '{{range .Mounts}}{{if eq .Destination "/etc/nginx/dhparam"}}{{.Name}}{{end}}{{end}}')
docker run -d \
--name nginx-proxy \
-p 80:80 -p 443:443 \
-v /docker/vol/etc/nginx/certs:/etc/nginx/certs \
-v /docker/vol/etc/nginx/conf.d:/etc/nginx/conf.d \
-v /docker/vol/etc/nginx/vhost.d:/etc/nginx/vhost.d \
-v /docker/vol/usr/share/nginx/html:/usr/share/nginx/html \
-v /var/run/docker.sock:/tmp/docker.sock:ro \
-v "${DHPARAM_VOL}:/etc/nginx/dhparam" \
nginxproxy/nginx-proxy:latest
# 4. Reconnect to additional networks (replicate original)
docker network connect test-net nginx-proxy
docker network connect prod-v-3-net nginx-proxy
docker network connect prod-v-4-net nginx-proxyVerify
# nginx config valid
docker exec nginx-proxy nginx -t
# Single upstream entry for v42-prod
docker exec nginx-proxy grep -A12 'upstream api.w4.pinbox24.com' \
/etc/nginx/conf.d/default.conf
# Expected: "test-net (ignored; reachable but redundant)" in comments
# Expected: exactly ONE `server <ip>:3000;` line
# Traffic flowing
curl -sk -o /dev/null -w '%{http_code}' -H 'Host: api.w4.pinbox24.com' \
https://localhost/health
# Expected: 200 or 404 (backend-dependent), NOT 502/503Rollback
If the new container fails:
docker stop nginx-proxy
docker rm nginx-proxy
docker run -d \
--name nginx-proxy \
-p 80:80 -p 443:443 \
-v /docker/vol/etc/nginx/certs:/etc/nginx/certs \
-v /docker/vol/etc/nginx/conf.d:/etc/nginx/conf.d \
-v /docker/vol/etc/nginx/vhost.d:/etc/nginx/vhost.d \
-v /docker/vol/usr/share/nginx/html:/usr/share/nginx/html \
-v /var/run/docker.sock:/tmp/docker.sock:ro \
-v "${DHPARAM_VOL}:/etc/nginx/dhparam" \
jwilder/nginx-proxy:pre-upgrade-YYYYMMDD # use your tagged date
docker network connect test-net nginx-proxy
docker network connect prod-v-3-net nginx-proxy
docker network connect prod-v-4-net nginx-proxyClean up old container after verification
docker rm nginx-proxy-old-jwilder
# Optional: remove old tag after a few days
# docker rmi jwilder/nginx-proxy:pre-upgrade-YYYYMMDDbms-1 state after 2026-07-08 swap
- Image:
nginxproxy/nginx-proxy:latest - Networks:
bridge,test-net,prod-v-3-net,prod-v-4-net - Bind mounts:
/docker/vol/etc/nginx/{certs,conf.d,vhost.d},/docker/vol/usr/share/nginx/html - Named volume:
5b9ea79f8933...→/etc/nginx/dhparam - letsencrypt companion:
nginx-proxy-letsencrypt(jrcs image) — unaffected by this swap - Pending: GitLab MR to commit
docker-compose.ymlchanges (see priorities.md)