Docker环境下Nginx反向代理多React应用SSL配置故障排查
我来帮你分析下这个问题,从你提供的错误日志一眼就能找到根源:Nginx正在尝试用HTTPS协议连接上游的app1和app2服务,但你的这两个React应用本身并没有配置SSL,完全是运行在HTTP协议下的。
看日志里的关键信息:upstream: "https://192.168.160.2:5000/app2",明明你在Nginx配置里写的proxy_pass是http://app1:5000,怎么突然变成HTTPS了?这大概率是因为你的React应用在生产环境下被配置了强制HTTPS重定向,当Nginx把外部的HTTPS请求转成HTTP转发给应用时,应用返回了301/302重定向到HTTPS版本的地址,而Nginx默认会自动跟随这个重定向,结果就跑去用HTTPS连接只支持HTTP的上游服务,自然就触发了SSL握手失败的错误。
下面是具体的解决方案,分三步来处理:
1. 取消React应用的强制HTTPS配置
对于用Create React App构建的应用,生产环境下如果设置了HTTPS=true环境变量,会强制应用使用HTTPS。你需要在docker-compose.yml里明确禁用这个设置:
services: app1: stdin_open: true build: app1/app1 networks: - local-network environment: - NODE_ENV=production - PORT=5000 - HTTPS=false # 新增这一行,确保应用不强制HTTPS app2: stdin_open: true build: app2/app2 networks: - local-network environment: - NODE_ENV=production - PORT=5000 - HTTPS=false # 同样新增这一行
如果是用其他工具(比如serve)部署的React应用,检查启动命令里有没有强制HTTPS的参数,直接去掉即可。
2. 优化Nginx配置,修正重定向问题
在Nginx的每个location块里添加proxy_redirect指令,确保上游返回的HTTPS重定向被修正为正确的路径,避免Nginx错误地用HTTPS连接上游:
location /app1 { 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-Proto $scheme; proxy_pass http://app1:5000; # 新增这一行,修正上游的HTTPS重定向 proxy_redirect https://$host http://$host; # WebSocket support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location /app2 { 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-Proto $scheme; proxy_pass http://app2:5000; # 新增这一行 proxy_redirect https://$host http://$host; # WebSocket support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
另外,你已经设置了X-Forwarded-Proto $scheme,这个很重要,它能让React应用感知到外部请求是通过HTTPS进来的,不会因为觉得自己在HTTP环境而触发不必要的重定向。
3. 提前处理React应用的子路径路由问题
虽然这和当前的SSL握手问题无关,但因为你是通过/app1和/app2的子路径访问应用,不配置的话后续会出现静态资源加载失败的问题:
- 在React应用的路由配置里,给
BrowserRouter添加basename属性:import { BrowserRouter } from 'react-router-dom'; ReactDOM.render( <BrowserRouter basename="/app1"> <App /> </BrowserRouter>, document.getElementById('root') ); - 构建应用时设置
PUBLIC_URL环境变量,比如:PUBLIC_URL=/app1 npm run build
最后验证
修改完成后,重启你的Docker服务:
docker-compose down && docker-compose up --build -d
然后访问https://xxx.xxx.xxx.xx/app1和https://xxx.xxx.xxx.xx/app2,应该就能正常访问了。
内容的提问来源于stack exchange,提问作者Fiphe

