“alert handshake failure”不是证书错误,而是TLS协商失败,需先据error.log中“to upstream”或“client:”锁定方向,再依次排查TLS版本、密码套件交集、SNI配置及OpenSSL错误码。

“alert handshake failure”不是证书错误,而是TLS协商卡在最开始——双方连用什么协议、什么加密方式都没谈拢。排查必须从日志方向切入,再逐层验证协议、套件、SNI等关键环节。
先看error.log锁定失败方向
打开 /var/log/nginx/error.log,别只盯着报错行,重点找它前后的上下文关键词:
- 出现 while SSL handshaking to upstream → Nginx 主动连后端 HTTPS 失败(比如
proxy_pass https://api.example.com) - 出现 while SSL handshaking, client: xxx.xxx.xxx.xxx → 浏览器或 App 连 Nginx 时失败(server 块配置问题)
绝大多数线上问题属于前者,但很多人一上来就查自己证书,绕远路。
客户端连Nginx失败:查协议版本与密码套件
日志含 client:,说明问题出在 server 块。重点验证两件事:
- 用 OpenSSL 测试服务器支持的最低 TLS 版本:
openssl s_client -connect yourdomain.com:443 -tls1_2 -servername yourdomain.com
若成功且返回Verify return code: 0 (ok),说明 TLS 1.2 可用;再试-tls1_1或-tls1,看是否报fatal handshake_failure - 检查双方是否有共用密码套件:
执行openssl s_client -connect yourdomain.com:443 -tls1_2 -cipher 'ALL:COMPLEMENTOFDEFAULT' 2>/dev/null | openssl cipher -v,列出服务器启用的套件;再比对客户端(如 Chrome 的chrome://settings/security)支持的套件,确认至少有一个交集,例如TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
Nginx连后端失败:盯紧SNI、协议和会话复用
日志含 to upstream,问题在 proxy_pass 配置。高频原因就三个:
-
协议写反了:后端只监听 HTTP(如 Spring Boot 的 8080),你却配成
proxy_pass https://127.0.0.1:8080。验证方法:curl -v http://127.0.0.1:8080能通,curl -v https://127.0.0.1:8080报错,基本就是它 -
SNI 没开:后端是多域名 HTTPS(如云 API、K8s Ingress),必须加
proxy_ssl_server_name on;;若用 IP 或泛域名,还得补proxy_ssl_name "api.example.com"; -
会话复用错乱:默认开启的
proxy_ssl_session_reuse on;在后端重启、证书轮换或负载节点不一致时容易失效,报ccs received early。临时关掉可快速验证:proxy_ssl_session_reuse off;
看OpenSSL错误码,比文字更准
error.log 中紧跟报错的十六进制码才是关键线索:
-
error:14094410→ handshake failure,大概率缺 SNI 或密码套件无交集 -
error:1408F10B→ wrong version number,基本是协议错配(HTTPS 配给 HTTP 后端) -
error:14209102→ unsupported protocol,比如proxy_ssl_protocols只开了 TLSv1.2,但后端只支持 TLSv1.3 -
error:141CF06C→ bad key share,TLS 1.3 密钥交换失败,常见于后端 OpenSSL 或 JDK 版本太老


















