nginx tls握手失败本质是ssl/tls协议协商中断,需先区分方向:日志含“to upstream”表明nginx作为客户端连后端失败,主因是协议误用、sni缺失(需proxy_ssl_server_name on)或ssl会话复用错乱;含“client: xxx”则为nginx服务端接收请求失败,常见于证书链不全、tls版本/密钥交换不兼容或ocsp stapling异常。

这个报错本质是 Nginx 在 TLS 握手阶段与上游(upstream)或客户端建立加密连接失败,不是配置写错那么简单,而是底层 SSL/TLS 协议栈在协商过程中被中断。关键要区分:是 Nginx 作为客户端去连上游 HTTPS 服务失败?还是 Nginx 作为服务端接收客户端 HTTPS 请求失败?方向错了,排查就全偏。
先确认错误发生的位置:上游代理 vs 客户端接入
看 error.log 中的上下文关键词:
- 出现 while SSL handshaking to upstream → 问题出在 Nginx 主动发起连接时,即
proxy_pass https://...配置环节 - 出现 while SSL handshaking, client: xxx(无 upstream 字样)→ 问题出在 Nginx 接收外部 HTTPS 请求时,即 server 块的 ssl 配置或证书链环节
绝大多数线上故障属于前者——Nginx 代理到后端 HTTPS 服务时握手崩了,但很多人一上来就查自己的证书,白忙半天。
针对 upstream 握手失败的三大高频根因
当错误日志明确带 to upstream,重点检查这三项:
-
协议误用:https:// 写成了 http://,或反过来
比如 upstream 实际只监听 HTTP(80 或非 443 端口),你却配成
proxy_pass https://172.16.40.36:9150,Nginx 就会强行走 TLS,对方返回乱码或直接断连,报wrong version number或tlsv1 alert internal error。验证方式:用curl -v http://ip:port和curl -v https://ip:port分别试,看哪个通。 -
SNI 缺失导致服务端无法选对证书
某些上游是多租户 HTTPS 服务(如云厂商 API、SaaS 后端),必须靠 SNI(Server Name Indication)告诉它“我要连的是哪个域名”。Nginx 默认不发 SNI,需显式开启:
proxy_ssl_server_name on;。否则可能触发sslv3 alert handshake failure。 -
SSL 会话复用引发状态错乱
proxy_ssl_session_reuse on(默认值)会让 Nginx 复用旧会话 ID 连接上游。但若上游服务重启、证书轮换或负载均衡节点不一致,复用的会话可能已失效,导致收到提前的 CCS 消息等异常,报ccs received early。临时解法:proxy_ssl_session_reuse off;。
针对客户端接入失败的典型线索
当错误指向 client IP,且没 upstream 字样,说明请求还没进业务逻辑就卡在 TLS 层:
-
证书链不完整
Nginx 只配了域名证书(crt),没配中间 CA 证书,客户端(尤其是 Android/iOS/Java 应用)校验失败,报
handshake failure。解决:用cat your_domain.crt intermediate.crt > fullchain.crt合并,并在配置中用ssl_certificate fullchain.crt。 -
TLS 版本或密钥交换算法不兼容
比如错误含
dh key too small,说明服务端 DH 参数强度低于客户端要求(常见于老版本 OpenSSL);含bad key share,多因客户端支持的密钥交换组(如 x25519)与 Nginx 配置的ssl_ecdh_curve不匹配。建议启用现代曲线:ssl_ecdh_curve secp384r1:prime256v1:x25519;。 -
OCSP Stapling 配置错误或上游不可达
若开了
ssl_stapling on但 OCSP 响应器超时或返回异常,部分严格客户端会拒绝握手。可先关掉观察:ssl_stapling off;。
快速定位技巧:用 OpenSSL 手动模拟握手
不依赖 Nginx 日志,直接验证链路是否健康:
- 测上游(Nginx 当客户端):
openssl s_client -connect 172.16.40.36:9150 -servername your-upstream-domain.com -tls1_2观察是否有 certificate、Verify return code、以及是否出现 read:errno=0 等异常。 - 测自身(Nginx 当服务端):
openssl s_client -connect your-nginx-ip:443 -servername your-domain.com注意看 Server certificate、SSL handshake has read X bytes 和 Verify return code 是否为 0。
只要 openssl 能通,基本排除网络和协议层问题;若不通,再对照错误码查 OpenSSL 官方文档(如 error:1408F10B 对应 wrong version number)。











