排查Nginx代理TLS协商异常,核心是确认Nginx作为HTTPS客户端连接上游是否完成握手:先通过error.log中“to upstream”锁定失败环节,再验证SNI是否开启并匹配(proxy_ssl_server_name on与proxy_ssl_name一致),最后实测协议/套件兼容性及证书链有效性。

排查 Nginx 代理转发中的 TLS 协商异常,核心是确认 Nginx 作为 HTTPS 客户端连接上游时是否成功完成握手。问题不在浏览器连 Nginx,而在 Nginx 连后端服务这一步。日志方向、SNI 行为、协议兼容性三者必须同步验证。
看 error.log 锁定真实失败环节
打开 /var/log/nginx/error.log,搜索 SSL_do_handshake() failed,重点看紧邻的上下文:
- 出现 while SSL handshaking to upstream → 确认是 Nginx 主动连后端失败,不是客户端访问问题
- 若同时有 no shared cipher 或 wrong version number,说明密码套件或协议版本不匹配
- 若报 tlsv1 alert unknown ca 或 certificate verify failed,大概率是上游返回了错误证书(如默认站点证书),根源常在 SNI 未发或发错
验证 SNI 是否真正发出并匹配
Nginx 默认不发送 SNI,多租户或泛域名后端必须显式开启并指定值:
- 配置中必须同时存在:proxy_ssl_server_name on; 和 proxy_ssl_name "api.example.com";(注意引号和分号)
- 若 proxy_pass 用的是 IP 地址,proxy_ssl_name 必须写死为后端证书 SAN 中存在的域名
- 用 openssl 模拟验证:
openssl s_client -connect 10.0.1.5:443 -servername api.example.com -showcerts 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName
观察输出是否含你期望的域名;若显示 subject=CN=*.internal,说明 SNI 不生效,上游 fallback 到了默认证书
检查协议与套件是否实际兼容
别只看配置写了什么,要看两端真实支持什么:
- 后端若为老旧系统(如 Java 8u161 以下、自建 Node.js 服务),可能不支持 TLSv1.3 或会话复用 → 加上 proxy_ssl_protocols TLSv1.2; 和 proxy_ssl_session_reuse off;
- 用 curl 直连测试:
curl -v https://10.0.1.5:443 --resolve "api.example.com:443:10.0.1.5"
看是否卡在 TLS handshake 或返回 SSL connect error - 若后端证书是国密双证书(SM2+RSA),标准 Nginx 无法解析 SM2 私钥 → 此类场景需使用 Tongsuo 编译的国密版 Nginx,否则握手必然失败
排除证书链与校验干扰
即使 SNI 正确、协议匹配,证书链问题也会中断握手:
- Nginx 默认校验上游证书(proxy_ssl_verify on; 是默认行为),若后端用私有 CA 或中间证书缺失,就会报 unknown ca
- 临时绕过验证可快速定位:proxy_ssl_verify off;(仅用于排查,不可上线)
- 更稳妥方式是配置可信 CA:proxy_ssl_trusted_certificate /path/to/upstream-ca-bundle.crt;,确保该文件包含后端证书链中所有非根 CA


















