proxy_ssl_verify_depth 控制 Nginx 验证后端 HTTPS 证书时信任链最大深度,需配合 proxy_ssl_verify、proxy_ssl_trusted_certificate、proxy_ssl_name 和 proxy_ssl_server_name 四项共同生效;设为 2 或 3 最平衡安全与兼容性。

proxy_ssl_verify_depth 控制的是 Nginx 在验证后端 HTTPS 服务证书时,最多向上追溯几级中间 CA 证书,它不单独生效,而是作为信任链校验的“长度闸门”,配合其他 SSL 验证指令共同构筑安全边界。
为什么这个值影响安全性?
设得太低(如 1):
- 只接受终端证书直连根 CA 的结构
- 遇到主流证书(如 Let’s Encrypt R3 → ISRG Root X1、DigiCert TLS EA)会直接失败,报
certificate verify failed - 表面“严格”,实则误拒合法链,反而可能被绕过(比如临时关掉验证)
设得太高(如 10):
- 允许过长、嵌套过深的中间签发路径
- 若后端配置松散或 PKI 管理不严,可能接纳来源不明、策略失控的中间 CA
- 削弱了证书链的可控性与可审计性
合理设置(通常是 2 或 3):
- 匹配真实部署结构,既不放行异常长链,也不卡死合规服务
- 是兼容性与最小信任原则的平衡点
必须同步配置的四个关键项
只改 proxy_ssl_verify_depth 没用,以下四项缺一不可:
proxy_ssl_verify on;
明确启用上游证书校验(默认是off,不开启等于裸连)proxy_ssl_trusted_certificate /path/to/ca-bundle.pem;
指向含完整信任链的 PEM 文件:必须包括所有中间 CA + 根 CA(顺序不限,但不能缺级)
✅ 推荐用 Mozilla 官方cacert.pem或企业私有 PKI 的全链 bundle
❌ 不能只放根证书,也不能混入私钥或后端终端证书proxy_ssl_name "backend.example.com";
显式声明期望的 SNI 主机名,用于匹配证书中的 SAN 字段
⚠️ 若proxy_pass用的是 IP 或变量(如https://$host:443),此项必填,否则校验直接失败proxy_ssl_server_name on;
启用 TLS SNI 扩展,确保握手时向后端发送正确域名
? 对接云 API、泛域名服务、mTLS 后端时必不可少
推荐取值与对应场景
proxy_ssl_verify_depth 1
仅适用于自签名证书、根 CA 直签场景(如测试环境单台服务)
需确保proxy_ssl_trusted_certificate中已包含该自签根证书proxy_ssl_verify_depth 2
覆盖绝大多数公网服务:Let’s Encrypt(R3 → ISRG Root X1)、Sectigo、ZeroSSL 等
是生产环境起步推荐值proxy_ssl_verify_depth 3
适配企业私有 PKI:如终端 → 部门 CA → 企业根 CA或含两级中间 CA 的云托管证书
安全团队评估链结构后可设为该值,兼顾纵深与可控
不建议设为
0(Nginx 不支持)或超过5(无实际必要,反增风险)
验证是否真正生效
修改后执行:
nginx -t && nginx -s reload
再检查:
-
错误日志:
/var/log/nginx/error.log中不再出现SSL_do_handshake() failed或certificate verify failed -
手动抓链:
openssl s_client -connect backend-ip:443 -servername backend.example.com -showcerts
观察输出中
-----BEGIN CERTIFICATE-----出现几次,确认链长是否在设定 depth 范围内 -
证书内容匹配:用
openssl x509 -in cert.pem -text -noout | grep -A1 "Subject Alternative Name"核对proxy_ssl_name是否与 SAN 完全一致(含通配符、大小写)
不复杂但容易忽略


















