Nginx校验客户端SSL证书有效性本质是启用mTLS,需同时配置ssl_verify_client on、ssl_client_certificate、ssl_certificate、ssl_certificate_key和ssl_verify_depth;单独设置任一参数均无效。

Nginx 校验客户端 SSL 证书有效性,本质是启用 TLS 双向认证(mTLS),由服务端验证客户端是否持有由指定 CA 签发、未过期、签名有效的证书。它不检查 SAN 或 CN 字段,也不做 OCSP 吊销实时查询(除非额外配置 stapling 或外部校验)。
必须配置的指令组合
单独设置任一参数都不生效,以下四项需同时存在且位置正确(均在 server 块内):
-
ssl_verify_client on | optional | off:控制强制校验行为-
on:客户端必须提供有效证书,否则直接返回 400(Bad Certificate) -
optional:允许无证书连接,但若提供了则仍会校验(结果通过$ssl_client_verify暴露)
-
-
ssl_client_certificate /path/to/ca-bundle.pem:指定可信 CA 证书文件(PEM 格式)- 必须是根 CA 或中间 CA 证书,不能是私钥、P12、DER 或客户端证书本身
- 多级 CA 可合并到一个文件(顺序不限,Nginx 自动构建信任链)
-
ssl_certificate和ssl_certificate_key:服务端自己的 HTTPS 证书与私钥(必需,否则无法建立 TLS 连接) -
ssl_verify_depth N:设置证书链最大验证深度- 默认为 1(仅支持终端证书 → 根 CA)
- 若客户端证书由中间 CA 签发(如 Let’s Encrypt R3 → ISRG Root X1),建议设为 2 或 3
证书文件准备要点
- 用
openssl x509 -in ca.crt -text -noout检查是否为有效 CA 证书,并确认Basic Constraints包含CA:TRUE - 文件权限设为
644,确保 Nginx worker 进程可读 - 不要混入私钥、服务端证书或客户端证书内容
路径级强制校验(非全局)
Nginx 不支持在 location 块中直接开启 mTLS,但可通过变量实现逻辑隔离:
- 全局启用
ssl_verify_client on(所有请求走握手校验) - 在目标路径中用
$ssl_client_verify判断并拦截:location /admin/ { if ($ssl_client_verify != "SUCCESS") { return 403 "Client certificate required and valid"; } proxy_pass http://backend; proxy_set_header X-Client-Verify $ssl_client_verify; proxy_set_header X-Client-DN $ssl_client_s_dn; }
验证通过后可用的变量
-
$ssl_client_verify:值为SUCCESS、FAILED:reason或NONE -
$ssl_client_s_dn:客户端证书的 Subject DN(如CN=user1,OU=dev,O=example) -
$ssl_client_cert:Base64 编码的完整 PEM 证书内容,可透传给后端
常见失败现象与排查
- 返回
400 Bad Request:客户端未提供证书,或证书格式错误(如 DER、P12) - 返回
403 Forbidden:证书已提供,但验证失败(过期、不被信任、链不全) - 错误日志出现
SSL_do_handshake() failed或certificate verify failed:- 开启
error_log /var/log/nginx/error.log debug;(临时)定位具体原因 - 检查
ssl_client_certificate文件路径、权限、内容合法性
- 开启
不复杂但容易忽略


















