Nginx反向代理HTTPS上游时出现502或SSL握手失败,主因是未发送SNI信息;需配置proxy_ssl_server_name on;并用proxy_ssl_name指定域名(如$host或$http_x_forwarded_host),同时配proxy_ssl_verify off、TLS版本等基础参数。

反向代理到外网 HTTPS 地址时出现 502、SSL_do_handshake() failed 或 peer closed connection in SSL handshake,绝大多数情况是 Nginx 在与上游服务器 TLS 握手时没发送正确的 SNI(Server Name Indication)信息,导致对方无法选择匹配的证书而直接断连。
必须开启并显式设置 SNI
Nginx 默认不会把 proxy_pass 中的域名作为 SNI 发送给上游——它只在自己作为 HTTPS 服务端时才自动处理 SNI。作为反向代理客户端,需手动启用:
- 添加
proxy_ssl_server_name on;启用 SNI 支持 - 用
proxy_ssl_name $host;动态传入客户端请求的 Host 域名(推荐$host,已标准化且不含端口) - 若上游要求固定域名(如 CDN 回源),可写死:
proxy_ssl_name "api.example.com";
注意 Host 头是否被中间层覆盖
如果上游是 CDN(如 Cloudflare、阿里云全站加速),它回源时往往会重写 Host 头为源站配置域名,此时 $host 就不是用户原始域名了。
- 让 CDN 透传原始 Host,例如通过
X-Forwarded-Host头 - 在 Nginx 中改用:
proxy_ssl_name $http_x_forwarded_host; - 同时确保该 header 未被 CDN 过滤或空值(可加
map做兜底)
验证上游是否真正支持 SNI
有些老旧负载均衡器、自建网关或内网服务可能未启用 SNI,或只认特定域名。
- 用 OpenSSL 直连测试:
openssl s_client -connect upstream-ip:443 -servername example.com - 检查返回的证书 Subject 和 SAN 是否包含目标域名
- 若不支持 SNI,该命令会返回默认证书或握手失败
其他关键配置项
光有 SNI 不够,还需配合基础 SSL 代理参数:
-
proxy_ssl_verify off;(若上游证书不可信或为自签) -
proxy_ssl_protocols TLSv1.2 TLSv1.3;(避免老协议兼容问题) -
proxy_set_header Host $host;(保持 Host 一致性,避免上游路由错乱) - 禁用
proxy_ssl_trusted_certificate等非必要校验,除非你主动管理 CA 信任链


















