必须将 error_log 设为 debug 级并确保编译含 --with-debug,才能记录 tls 握手失败详情;需结合 openssl 错误码(如 1417d18d 表示 version too low)、上下文关键词(to upstream 或 client: xxx)精准定位方向与根因,并辅以 stream 模块和 tcpdump 验证底层异常。

要让 Nginx 记录 TLS 握手失败的详细原因,不能只靠默认 error_log,必须组合启用 OpenSSL 调试能力与 Nginx 日志控制——关键不是“记更多”,而是“记对层”。
开启 SSL 模块 debug 级日志输出
Nginx 默认 warn 级别不输出握手协商细节。需在 http 或 server 块中显式设置:
- 添加 error_log /var/log/nginx/ssl_debug.log debug;(路径可自定义)
- 确保 Nginx 编译时含 --with-debug(主流发行版二进制包通常已支持;验证命令:
nginx -V 2>&1 | grep with-debug) - 重启后,日志中会出现类似:
SSL_do_handshake() failed (SSL: error:1417A0C1:SSL routines:tls_post_process_client_hello:no shared cipher)
捕获 OpenSSL 底层错误码和上下文
OpenSSL 错误码才是精准定位依据,它紧跟在失败提示后,比文字描述更可靠:
-
error:1417D18D → version too low:客户端 TLS 版本低于
ssl_protocols允许范围 -
error:1417A0C1 → no shared cipher:服务端
ssl_ciphers与客户端无交集 - error:14094410 → handshake failure:常见于 SNI 缺失、证书链不全或客户端证书未提供
- error:1408F10B → wrong version number:典型协议错配,如 proxy_pass https:// 指向 HTTP 后端
区分握手方向,避免误判根因
同一行 SSL_do_handshake() failed 可能指向完全不同的问题,看紧邻的上下文关键词:
- 出现 while SSL handshaking to upstream → Nginx 是客户端,问题出在连后端(如 Java API、Kibana),检查
proxy_ssl_protocols、proxy_ssl_server_name on和proxy_ssl_name - 出现 while SSL handshaking, client: xxx.xxx.xxx.xxx → Nginx 是服务端,问题出在浏览器/App 连接你,重点查证书链、TLS 版本兼容性及 cipher 支持
补充 stream 层原始连接日志(用于 TCP 级异常)
当握手失败发生在更底层(如 ClientHello 格式错误、立即 RST),HTTP 日志完全空白。此时启用 stream 模块记录原始连接行为:
- 在顶层配置
stream { include /etc/nginx/stream.d/*.conf; } - 新建
/etc/nginx/stream.d/tls-fail-log.conf,监听 443 并记录连接状态、耗时、是否超时 - 配合
tcpdump -w tls-fail.pcap port 443抓包,再用openssl s_client -connect ... -debug -msg解析握手流程











