Nginx代理HTTPS请求至HTTP后端时,必须配置proxy_pass为http://并透传X-Forwarded-Proto $scheme,同时禁用所有proxy_ssl_*指令,否则将因强制TLS握手导致502或连接失败。

当 Nginx 以 HTTPS 接收客户端请求,却将流量代理到一个仅支持 HTTP 的后端服务(例如本地运行的 Flask、Django 开发服务器或未启用 TLS 的 Node.js 应用)时,若配置不当,会出现 SSL 握手失败、502 错误、连接被拒绝等现象。根本原因在于:Nginx 尝试与后端建立 HTTPS 连接,而后端根本没有监听 HTTPS 端口或不提供 TLS 服务。
确认后端协议类型
先明确后端是否真的只支持 HTTP:
- 检查后端监听地址,如
http://127.0.0.1:8000或localhost:3000—— 若 URL 以http://开头且无证书配置,即为纯 HTTP 服务 - 用
curl -v http://127.0.0.1:8000/health测试通路;再试curl -v https://127.0.0.1:8000/health,后者应直接失败(Connection refused 或 SSL error) - 避免在
proxy_pass中错误写成https://...,这是最常见误配
正确设置 proxy_pass 为 HTTP
Nginx 必须显式使用 HTTP 协议转发给后端,即使自己对外是 HTTPS:
- 确保
proxy_pass指令以http://开头,例如:proxy_pass http://127.0.0.1:8000; - 不要写成
https://127.0.0.1:8000或https://backend(除非后端真有 HTTPS) - 若使用
upstream,定义中也必须是 HTTP:upstream django_app { server 127.0.0.1:8000; }(无ssl关键字)
透传原始 HTTPS 协议信息
后端虽不处理 TLS,但仍需知道用户最初是通过 HTTPS 访问的,否则会生成 HTTP 链接、拒绝 CSRF、报错重定向循环等:
- 添加关键头:
proxy_set_header X-Forwarded-Proto $scheme;
($scheme在 HTTPS 请求下自动为https) - 同时传递真实客户端 IP:
proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - 确保 Host 头准确:
proxy_set_header Host $host;(非$http_host,避免带端口)
关闭不必要的 SSL 代理参数
对纯 HTTP 后端启用 SSL 相关指令,会导致握手强制发起并失败:
- 删除或注释掉以下配置(它们只适用于后端也走 HTTPS 的场景):
proxy_ssl_verify off;proxy_ssl_server_name on;proxy_ssl_name ...; - 确认没有
proxy_ssl_*类指令残留,尤其在 copy-paste 配置时易遗漏 - 无需配置
ssl_certificate相关项——那是给 Nginx 自己对外 HTTPS 用的,与后端无关


















