Nginx无法在access_log中记录证书链验证失败,因该失败发生在TLS握手阶段、早于HTTP请求处理;需通过error_log(warn/debug级)捕获OpenSSL错误(如unable to get local issuer certificate),结合openssl s_client验证证书链完整性,并确保ssl_certificate文件包含完整证书链。

Nginx 本身无法在 access_log 中记录证书链验证失败的访问,因为这类失败发生在 TLS 握手阶段,早于 HTTP 请求处理。客户端(如浏览器)在收到服务端证书后、尚未发送任何 HTTP 请求前,就因证书链不完整、CA 不可信、中间证书缺失或签名无效等原因终止连接。此时 Nginx 根本收不到 $request,access_log 完全空白,$status 等字段也无从生成。
但你可以通过以下方式捕获、定位并间接审计证书链验证失败问题:
✅ 启用 OpenSSL 级别错误日志,暴露握手失败原因
这是最直接有效的方式。证书链问题(如 unknown ca、unable to get local issuer certificate)会由 OpenSSL 报出,并写入 Nginx 的 error_log(需 debug 或 warn 级别):
http {
error_log /var/log/nginx/error.log warn; # 至少设为 warn
ssl_log_level warn; # Nginx 1.19.4+ 支持,控制 SSL 错误输出粒度
}
重启后,典型日志条目如下:
2026/09/30 21:45:12 [warn] 12345#0: *6001 SSL_do_handshake() failed (SSL: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:reason:unable to get local issuer certificate) while SSL handshaking
该日志明确指出是「无法获取本地签发者证书」——即客户端缺少中间 CA 或服务端未正确配置 ssl_trusted_certificate / 未拼接完整证书链。
✅ 验证并强制使用完整证书链文件
Nginx 不自动补全中间证书。必须确保 ssl_certificate 指向的 .crt 文件包含服务器证书 + 全部中间证书(按顺序),例如:
ssl_certificate /etc/nginx/ssl/example.com.crt; # 内容应为: # -----BEGIN CERTIFICATE----- ← 你的域名证书 # ... # -----END CERTIFICATE----- # -----BEGIN CERTIFICATE----- ← 中间 CA 证书(如 Sectigo/R3) # ... # -----END CERTIFICATE-----
若使用单独的中间证书文件,可用 cat example.com.crt intermediate.pem > fullchain.crt 合并,并用 openssl verify -CAfile fullchain.crt example.com.crt 本地验证链有效性。
✅ 使用 openssl s_client 主动探测链完整性
在服务端或第三方机器执行,模拟客户端行为并查看详细验证过程:
openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null | openssl x509 -noout -text | grep -A1 "Issuer\|Subject"
重点关注输出中是否出现 Verify return code: 0 (ok);若为 21 (unable to verify the first certificate) 或 19 (self signed certificate in certificate chain),说明链配置有误。
✅ (可选)配合 stream 模块记录 TLS 连接异常模式
对高频失败连接(如大量短连接、超时),可在 stream 块中启用基础连接日志,辅助识别异常流量特征:
stream {
log_format tls_conn '$remote_addr [$time_local] $protocol $status $upstream_addr $session_time';
access_log /var/log/nginx/tls_conn.log tls_conn;
server {
listen 443;
proxy_pass backend_https;
proxy_timeout 3s;
}
}
状态码为 502 或 session_time 接近 proxy_timeout,常对应 TLS 握手卡死——可能源于证书链不被客户端信任导致协商停滞。
Nginx 不参与证书链验证,只负责原样发送。真正决定“验证失败”的是客户端。所以重点不在“记录失败访问”,而在于提前发现并修复链配置缺陷——靠日志定位 + 主动验证 + 正确拼接证书文件,三者结合才可靠。











