DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

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 检查语法,再在维护窗口重载或重建相关服务。失败时恢复原文件并再次检查语法。验收既要看代理入口返回应用预期内容,也要看错误日志不再出现同一条连接失败;如果后端不需要公网直连,还应确认没有因排查而意外扩大端口暴露范围。