解决nginx反向代理https握手失败,关键先据error.log中“to upstream”或“client: xxx”区分方向:前者需检查proxy_pass协议匹配、启用proxy_ssl_server_name on并配proxy_ssl_name、禁用proxy_ssl_*指令(若后端为http);后者查证书链、tls版本兼容性。

解决 Nginx 反向代理导致的 HTTPS 握手失败,关键在于区分“Nginx 对外接收客户端连接”和“Nginx 对内连接后端服务”两个环节——失败发生在哪一侧,处理方式完全不同。多数线上问题实际出在后者:Nginx 与后端 HTTPS 服务建立 TLS 连接时握手失败,表现为 502、日志中出现 SSL_do_handshake() failed 或 while SSL handshaking to upstream。
确认失败方向:先看 error.log 关键词
打开 /var/log/nginx/error.log,不要只盯着报错行,重点看它前后的上下文:
- 如果错误紧邻 while SSL handshaking to upstream → 是 Nginx 主动连后端 HTTPS 失败(配置重点在
location块) - 如果错误紧邻 client: xxx.xxx.xxx.xxx → 是浏览器或 APP 连 Nginx 失败(问题在
server块的 SSL 配置)
后端 HTTPS 连接失败:SNI、协议、证书三要素缺一不可
当 Nginx proxy_pass 指向 https:// 地址时,必须满足以下条件才能完成 TLS 握手:
-
开启 SNI 发送能力:在
location块中添加proxy_ssl_server_name on;(不能写在upstream或http块) -
指定 SNI 域名值:紧随其后配
proxy_ssl_name "api.example.com";(双引号必需);多域名场景推荐proxy_ssl_name $host;(确保 $host 不含端口) -
proxy_pass 必须用域名:写成
proxy_pass https://api.example.com/;,不能是 IP(如https://10.10.20.30/),否则 SNI 字段为空 -
Host 请求头需一致:加
proxy_set_header Host $host;,避免 SNI 是api.example.com而 Host 是api.example.com:443 -
证书有效性要验证:若后端证书过期或域名不匹配,可临时设
proxy_ssl_verify off;测试,但生产环境应配置proxy_ssl_trusted_certificate或联系上游更新证书
后端其实是 HTTP:别让 Nginx 强制走 TLS
常见误配是 proxy_pass https://127.0.0.1:8000,但后端只监听 http://127.0.0.1:8000。此时 Nginx 会尝试发起 HTTPS 连接,必然失败:
-
proxy_pass 必须为 http://:例如
proxy_pass http://127.0.0.1:8000; -
透传原始协议信息:加
proxy_set_header X-Forwarded-Proto $scheme;,让后端知道用户访问的是 HTTPS -
禁用所有 proxy_ssl_* 指令:包括
proxy_ssl_verify、proxy_ssl_server_name等,它们在此场景下完全无效且引发错误
WebSocket 握手失败:不是 TLS 问题,而是协议升级被拦截
访问 wss:// 报 400 或 “handshake failed”,通常不是证书或 SNI 问题,而是 Nginx 没正确传递升级请求:
-
强制 HTTP/1.1:加
proxy_http_version 1.1; -
透传 Upgrade 和 Connection 头:加
proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection "upgrade"; -
调整超时:WebSocket 长连接需延长超时,如
proxy_read_timeout 86400;











