必须启用 proxy_ssl_server_name on 并显式设置 proxy_ssl_name,否则 Nginx 与 HTTPS 后端 TLS 握手必然失败导致 502;验证方法包括查 error.log 中 SSL_do_handshake() 失败日志、curl 直连对比域名/IP 访问结果;proxy_ssl_name 必须为带引号的字面量且与 Host 头严格一致,proxy_ssl_server_name 默认关闭,不会自动触发。

必须启用 proxy_ssl_server_name on 并显式设置 proxy_ssl_name,否则 Nginx 与外网 HTTPS 后端的 TLS 握手必然失败,502 不可避免。
怎么确认是 SNI 缺失导致的 502
别急着改配置,先验证是不是这个问题:
- 查
/var/log/nginx/error.log,重点找SSL_do_handshake() failed、tlsv1 alert internal error或temporarily disabled while SSL handshaking to upstream - 用
curl -v https://your-upstream-domain直连后端,能通但 Nginx 代理不通,基本锁定 SNI - 看日志里 Nginx 解析出的 IP,再用
curl -v https://IP试 —— 如果直接 IP 访问失败,而域名能通,就是典型 SNI 依赖场景
proxy_ssl_server_name 和 proxy_ssl_name 必须成对出现
proxy_ssl_server_name on 只是开关,它不决定发哪个域名;真正控制 SNI 字段值的是 proxy_ssl_name,且必须是字符串字面量(带引号):
- 如果
proxy_pass直写 HTTPS 域名,比如proxy_pass https://api.example.com/;,就在同个location块里加:proxy_ssl_server_name on; proxy_ssl_name "api.example.com";
- 如果用了
upstream,比如upstream backend { server api.example.com:443; },proxy_ssl_name依然要写,且值必须和 upstream 中的域名一致 —— Nginx 不会自动从 upstream 解析结果中提取 SNI 值 -
proxy_ssl_name的值不能是变量(如$host),也不能省略引号,否则配置加载失败或 SNI 发送错误
Host 头和 SNI 域名必须严格一致
部分后端(如 Istio sidecar、某些云 API 网关)不仅校验 SNI,还比对 Host 请求头。两者不一致时,可能跳过证书匹配直接拒绝连接:
- 务必显式设置
proxy_set_header Host "api.example.com";,不要用$host或$http_host—— 它们可能被客户端污染 - 这个值必须和
proxy_ssl_name完全相同(包括大小写、有无端口),否则等于白配 - 若后端要求带端口(如
api.example.com:443),SNI 和 Host 都得带上,但多数情况只写域名即可
忽略证书校验只是临时手段,别在生产环境开 proxy_ssl_verify off
开了 proxy_ssl_verify off 能绕过证书错误,但它掩盖了真实问题,且不解决握手失败本身:
- SNI 缺失导致的 502,发生在证书校验之前 —— 连握手都没完成,证书对错根本没机会判断
- 如果你开了
proxy_ssl_verify off后 502 消失了,大概率是别的配置(比如超时、缓冲区)同时出了问题,SNI 仍没配对 - 生产环境必须配
proxy_ssl_trusted_certificate指向可信 CA 证书包,并确保后端证书域名与proxy_ssl_name匹配
最常被忽略的一点:proxy_ssl_server_name 默认是 off,且没有任何隐式触发逻辑 —— 即使你 proxy_pass https://xxx 写了域名,Nginx 也绝不会自动开启它。不显式写,就永远没有 SNI。











