需启用Nginx debug级SSL日志(error_log debug)并确认编译含--with-debug,结合ssl_protocols、ssl_ciphers等配置,才能捕获TLS版本不匹配、证书验证失败、SNI缺失、ALPN协商异常等底层握手错误。

默认情况下,Nginx 的 error_log 只记录严重错误(如 SSL 握手失败的简略信息),不会输出 TLS 协议层的详细失败原因(比如不支持的协议版本、密码套件不匹配、证书验证失败、SNI 不匹配、ALPN 协商失败等)。要获取详细的 SSL 握手失败日志,需结合 Nginx 编译选项、日志级别、调试模块和 OpenSSL 行为综合配置。
启用高精度错误日志级别
Nginx 必须以 debug 级别启动才能输出 SSL 握手过程中的关键状态。注意:该级别会产生大量日志,仅用于排查,不可长期开启。
- 确保编译 Nginx 时启用了
--with-debug(检查nginx -V 2>&1 | grep -- '--with-debug') - 在主配置块(
nginx.conf最外层)设置:
error_log /var/log/nginx/error.log debug; - 重启 Nginx:
nginx -t && nginx -s reload
强制记录 SSL 握手关键事件
仅靠 debug 日志还不够——部分握手失败(如 Client Hello 被直接拒绝)可能不触发常规日志。可通过以下方式增强捕获:
- 在
server块中添加:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:...;
ssl_prefer_server_ciphers off;
避免因协议/密码配置过严导致静默失败 - 启用
ssl_verify_client optional_no_ca并配合$ssl_client_verify变量,可在log_format中记录客户端证书验证结果 - 自定义日志格式示例(加入 SSL 关键变量):
log_format ssl_debug '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'"$ssl_protocol" "$ssl_cipher" "$ssl_client_verify" "$ssl_server_name";
借助 OpenSSL 工具辅助定位
Nginx 本身不提供类似 OpenSSL s_client -debug 的原始字节级日志。但可配合外部工具交叉验证:
- 用
openssl s_client -connect your.domain:443 -tls1_2 -cipher 'ECDHE-RSA-AES128-SHA' -msg模拟握手,观察哪一步失败 - 抓包分析:
tcpdump -i any -s 0 -w ssl.pcap port 443,用 Wireshark 打开,过滤tls.handshake.type == 1(Client Hello)和== 2(Server Hello),查看是否返回 Alert - 检查系统 OpenSSL 版本是否过旧(如 RHEL/CentOS 7 默认 OpenSSL 1.0.2 不支持 TLS 1.3),升级或重编译 Nginx 链接新版 OpenSSL
常见握手失败原因与对应日志特征
开启 debug 日志后,典型失败会在 error.log 中出现如下线索:
-
no suitable key share → TLS 1.3 握手失败,客户端未提供服务端支持的密钥交换组(如服务端只配了
ssl_ecdh_curve secp384r1,但客户端只支持x25519) -
SSL_do_handshake() failed (SSL:) ... no protocols available →
ssl_protocols配置与客户端支持协议无交集 - SSL alert number 40(handshake_failure)→ 通用握手失败,需结合前后日志看是 Server Hello 后立即断连,还是 Certificate Verify 失败
-
client sent fatal alert: unknown_ca → 客户端证书被拒绝,通常因
ssl_client_certificate指向的 CA 文件缺失或不匹配


















