ssl_verify_depth 表示客户端证书链中中间 ca 的数量,不包含根 ca:根 ca 直签设为 1,1 级中间 ca 设为 2,2 级中间 ca 设为 3;必须配合 ssl_client_certificate 包含完整信任链,并用 openssl verify 验证链完整性。

在 Nginx 双向认证(mTLS)中,ssl_verify_depth 不是“证书总级数”,而是指从客户端终端证书向上追溯时,**最多允许经过多少级中间 CA**——即验证链中中间证书的数量,不包含根 CA 本身。
怎么算清层级:看签发路径
关键看客户端证书是怎么被签发出来的:
- 客户端证书由根 CA 直接签发 → 链中无中间 CA → ssl_verify_depth 应设为 1
- 客户端证书由 1 级中间 CA 签发(该中间 CA 由根 CA 签)→ 链含 1 级中间 CA → ssl_verify_depth 应设为 2
- 客户端证书由 2 级中间 CA 签发(根 → 中间1 → 中间2 → 客户端)→ 链含 2 级中间 CA → ssl_verify_depth 应设为 3
为什么默认值 1 常常不够用
默认 ssl_verify_depth 1 表示只接受“根 CA 直签”或“自签名”证书。但生产环境普遍使用中间 CA 分层管理,比如:
- 根 CA 用于离线保护,不直接对外签发
- 中间 CA 负责批量签发客户端证书
- 此时客户端证书的签发链是:客户端 ← 中间 CA ← 根 CA
- Nginx 验证时需先用中间 CA 验证客户端证书,再用根 CA 验证中间 CA —— 这需要深度为 2
配套必须做对的两件事
仅调大 ssl_verify_depth 不够,还需同步满足:
- ssl_client_certificate 指定的 PEM 文件里,必须同时包含中间 CA 和根 CA 的证书(顺序不限,但缺一不可)
- 本地用 openssl verify 验证链是否完整: openssl verify -CAfile ca-chain.pem client.crt 若返回 OK,说明链完整;若报 unable to get issuer certificate,则链缺失或 depth 设置不足
常见错误表现与定位
当 ssl_verify_depth 设置偏小时,Nginx 日志中通常出现:
- $ssl_client_verify = "FAILED:unable to get issuer certificate"
- 客户端收到 HTTP 400 错误(而非 403),因为失败发生在 TLS 握手阶段,尚未进入 HTTP 层
- 即使客户端证书本身有效、未过期、未吊销,仍被拒绝











