Nginx 容器反向代理出现 502:localhost 指向了哪里
宿主机能访问后端,Nginx 容器却返回 502?结合网友的 Nextcloud 案例,区分宿主机与容器 localhost,核对内部端口和共同网络。
后端通过宿主机的 127.0.0.1:8080 能打开,放在另一个容器里的 Nginx 却返回 502 Bad Gateway,错误日志出现 connect() failed (111: Connection refused) while connecting to upstream。先看 proxy_pass 的地址:普通桥接网络中,Nginx 容器内的 127.0.0.1 指 Nginx 容器自身,不能用它访问另一个容器或宿主机上的服务。
宿主机可访问,不代表代理容器可访问
应用发布为 127.0.0.1:8080:80,适合宿主机通过 8080 访问;Nginx 也在容器里时,proxy_pass http://127.0.0.1:8080 会把请求发回 Nginx 容器自身。绕到 Docker 网关再回容器会增加依赖,写死网关 IP 也不利于重建。
普通 Compose 部署可以先使用共同网络中的服务名,确认内部连接恢复后,再处理应用自身的可信域名或代理配置。网络转发与应用配置是两个步骤,改对上游地址不保证所有应用层错误都同时消失。
根据 Nginx 所在位置选择上游
同一个后端,代理地址取决于代理运行在哪里:
| Nginx 的位置 | 后端的位置 | 通常使用的目标 |
|---|---|---|
| 宿主机进程 | 容器,发布为 127.0.0.1:8080:80 |
127.0.0.1:8080 |
| 普通桥接网络中的容器 | 同网络容器,服务名 app,内部监听 80 |
app:80 |
| 普通桥接网络中的容器 | 宿主机进程 | 按平台配置宿主机可达地址,并核对监听范围 |
这个判断不适用于 host 网络或显式共享网络命名空间。Docker Desktop 与原生 Linux 的宿主机访问方式也有区别,不能在没有确认平台时把某个网关 IP 当作通用值。
端口映射的左侧属于宿主机,右侧属于容器。8080:80 中,另一个容器通常访问内部的 80;它没有必要先绕到宿主机的 8080。
先用日志区分拒绝、解析与超时
查看当前配置和最近的错误记录:
# 假设服务名为 nginx 和 app
docker compose logs --tail=100 nginx
docker compose ps
docker compose exec nginx nginx -T
docker inspect --format '{{json .NetworkSettings.Networks}}' \
"$(docker compose ps -q nginx)"
docker inspect --format '{{json .NetworkSettings.Networks}}' \
"$(docker compose ps -q app)"
nginx -T 会检查并打印加载的配置,重点看真实生效的 proxy_pass;不要只查看宿主机上一份未挂载进去的文件。两个容器的网络列表应有共同网络。输出可能包含内部地址或配置中的凭据,分享前脱敏。
若日志目标是 127.0.0.1:8080,而 Nginx 与应用各在独立容器中,先修正地址。若是 host not found in upstream,检查服务名和共同网络。若已解析到应用 IP,却被拒绝,核对应用内部端口、监听地址和是否启动完成。若是超时,继续看网络路径或应用处理时间;不要把所有 502 都归因于同一个 localhost 问题。
需要进一步确认时,可以从代理容器访问上游,但前提是镜像已包含工具:
docker compose exec nginx curl -sS -D - http://app:80/
没有 curl 时,先采用已有诊断工具或独立的受控诊断环境。不要为排查方便临时修改生产容器,再把这种改动误当成下一次重建仍会保留的配置。
两个容器同网时,使用服务名和内部端口
下面展示网络相关的配置片段;应用镜像、数据库及持久化目录应保留你已有的设置:
services:
nginx:
image: nginx:stable
ports:
- "80:80"
volumes:
- ./proxy.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- backend
app:
# 保留已有 image/build 和应用配置
networks:
- backend
networks:
backend:
相应的 HTTP 代理片段如下,前提是应用确实监听容器内的 80:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://app:80;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
它只说明内部转发路径,不包含 HTTPS、WebSocket 或某个应用完整的代理要求。需要这些能力时按应用和 Nginx 文档增加配置。后端若使用 HTTPS,也要匹配协议及证书要求,不能只改端口。
两个服务若分别在不同 Compose 项目里,默认网络通常也不同;要显式连接到同一个受控网络,再核对服务别名。后端重建后 IP 可能变化,旧版或某些配置下 Nginx 仍持有旧解析结果,需按版本安排重新解析或重新加载配置,不能承诺服务名在所有配置中都自动消除这个问题。
代理通了以后,再处理应用层拒绝
网络连接恢复后,如果 Nextcloud 等应用返回可信域名、重定向或反向代理相关错误,应按应用要求继续处理。这已经不同于 Nginx 无法连接上游的 502。保留原始错误和新的响应,避免把两个阶段混在一起。
上线前保存配置,先执行 nginx -t 检查语法,再在维护窗口重载或重建相关服务。失败时恢复原文件并再次检查语法。验收既要看代理入口返回应用预期内容,也要看错误日志不再出现同一条连接失败;如果后端不需要公网直连,还应确认没有因排查而意外扩大端口暴露范围。


