Docker化Nginx反向代理对接React与Express应用时出现502 Bad Gateway错误的排查求助
排查Docker Compose + Nginx 502 Bad Gateway问题
让我们一步步拆解你遇到的问题,核心原因主要集中在服务依赖顺序、应用监听端口配置以及Nginx代理目标端口匹配这几个点上:
一、最关键的问题:服务启动顺序搞反了
你的docker-compose.yml里让client和server依赖reverse-proxy,这意味着Nginx会先启动,而此时React和Express服务还没就绪。Nginx启动时会尝试解析http://client和http://server,但这两个容器可能还没完全启动,导致Nginx无法建立连接,直接返回502。
修复方案:把依赖关系反过来,让reverse-proxy依赖client和server,确保Nginx在后端服务就绪后再启动:
version: "3" services: reverse-proxy: image: mern-reverse-proxy build: ./reverse-proxy container_name: mern-app-reverse-proxy ports: - "80:80" depends_on: # 这里修改为依赖client和server - client - server client: image: mern-react build: ./client volumes: - ./client/:/usr/src/app - /usr/src/app/node_modules container_name: mern-app-client environment: CHOKIDAR_USEPOLLING: "true" PORT: 3000 # 新增:指定React监听端口 HOST: 0.0.0.0 # 新增:让React监听所有网卡(容器内必须配置) server: image: mern-express build: ./server volumes: - ./server/:/usr/src/app - /usr/src/app/node_modules container_name: mern-app-server environment: CHOKIDAR_USEPOLLING: "true"
二、应用实际监听端口与配置不匹配
你在Dockerfile里EXPOSE 80,但默认情况下:
- React的
yarn start默认监听3000端口,且只监听localhost(容器内无法被其他容器访问) - Express默认监听3000端口(如果你的代码没改的话)
这就导致Nginx尝试代理到服务的80端口时,根本没有服务在监听,直接连接失败。
针对React的修复:
修改React的Dockerfile,把EXPOSE改成实际监听的3000端口:
FROM node:16-alpine3.11 WORKDIR /usr/src/app COPY ./package.json ./ COPY ./yarn.lock ./ RUN yarn install COPY . . EXPOSE 3000 # 从80改成3000 CMD ["yarn", "start"]
针对Express的修复:
- 修改Dockerfile的
EXPOSE为3000:
FROM node:16-alpine3.11 WORKDIR /usr/src/app COPY ./package.json ./ COPY ./yarn.lock ./ RUN yarn install COPY . . EXPOSE 3000 # 从80改成3000 CMD ["yarn", "start"]
- 确保Express代码监听
0.0.0.0(容器内必须配置,否则只能本地访问):
// Express入口文件示例 app.listen(3000, '0.0.0.0', () => { console.log('Server running on port 3000'); });
三、Nginx代理目标端口需要明确指定
现在你的nginx.conf里proxy_pass http://client和http://server没有指定端口,Nginx会默认用80端口,但我们的服务实际在3000端口运行,所以必须补上端口:
worker_processes 1; events { worker_connections 1024; } http { sendfile on; server { listen 80; location /api { proxy_pass http://server:3000; # 加上3000端口 proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $server_name; } location / { proxy_pass http://client:3000; # 加上3000端口 proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $server_name; } } }
额外排查技巧
如果修改后还是有问题,可以通过以下命令定位:
- 进入Nginx容器测试网络连通性:
能ping通说明Docker网络没问题。docker exec -it mern-app-reverse-proxy ping client docker exec -it mern-app-reverse-proxy ping server - 在Nginx容器内测试服务端口是否可达:
能返回内容说明服务正常,否则检查服务是否启动。docker exec -it mern-app-reverse-proxy curl http://client:3000 docker exec -it mern-app-reverse-proxy curl http://server:3000/api/xxx # 替换成你的API路径 - 查看Nginx错误日志:
日志里会明确显示是连接超时还是拒绝连接,帮助快速定位问题。docker logs mern-app-reverse-proxy
内容的提问来源于stack exchange,提问作者Vid
相关产品推荐
相关产品推荐

