proxy_ssl_verify_depth必须设为与后端证书链中间证书数量匹配的值,并严格配合proxy_ssl_verify on、proxy_ssl_trusted_certificate、proxy_ssl_name和proxy_ssl_server_name四项指令共同生效,缺一则静默降级。

要让 proxy_ssl_verify_depth 真正起作用,它不能单独配置,必须和证书验证的完整链条对齐——设小了会 502,设大了可能放行异常长链,关键在“匹配真实结构+配齐四要素”。
先确认后端证书链到底有几级
别猜,用 OpenSSL 实测:
- 运行 openssl s_client -connect backend-svc:443 -servername backend-svc.internal -showcerts 2>/dev/null | grep "BEGIN CERTIFICATE" | wc -l,输出数字就是返回的证书总数(含终端 + 所有中间)
- 再看证书内容:openssl x509 -in service.crt -text -noout | grep "CA Issuers",每出现一次有效链接,就代表一级中间签发关系
- 最终 depth 值 = 中间证书数量(不含终端证书,也不含根 CA,但根 CA 必须出现在 trusted_certificate 文件中)
必须同时配齐这四项,缺一不可
只改 proxy_ssl_verify_depth 是无效的,Nginx 会静默降级为不校验:
- proxy_ssl_verify on; —— 明确打开上游证书校验开关(默认是 off)
- proxy_ssl_trusted_certificate /etc/nginx/certs/ca-bundle.pem; —— 文件里必须包含整条链中所有非终端证书:根 CA + 所有中间 CA(顺序无关,但缺一级都不行)
-
proxy_ssl_name "backend-svc.internal"; —— 显式声明期望的 SNI 主机名,用于匹配证书中的 SAN 字段;若
proxy_pass写的是 IP 或变量,此项必填 - proxy_ssl_server_name on; —— 启用 TLS SNI 扩展,确保握手时把域名发给后端,避免返回默认或不匹配证书
推荐取值与对应场景
不是越大越安全,也不是越小越严格,而是刚好覆盖你的真实链结构:
- depth 1:仅适用于自签名证书、或根 CA 直接签发服务证书的极简环境;需确保 trusted_certificate 中已包含该自签根
- depth 2:覆盖 Let’s Encrypt R3、Sectigo、ZeroSSL 等主流商业证书(终端 → 中间 CA → 根 CA),是公网服务和多数云 API 的推荐起点
- depth 3:适配企业私有 PKI 中含两级中间 CA 的结构(如 终端 → 部门 CA → 企业根 CA),内网微服务常见,建议生产环境从 3 起步并验证
- depth ≥4:除非你明确使用了三级及以上嵌套中间 CA,否则不建议;链越长,可审计性越弱,潜在信任风险越高
验证是否真正生效
重载 Nginx 后不能只看启动成功,要实测握手行为:
- 发起请求后查 error.log:若无
SSL_do_handshake() failed或certificate verify failed类报错,说明校验已通过 - 用 curl -v https://nginx-domain/api/ 观察输出,看到
SSL certificate verify ok是最直接的确认信号 - 若仍失败,重点排查三项:后端是否返回完整证书链?trusted_certificate 是否漏掉某一级中间 CA?proxy_ssl_name 是否与证书 SAN 完全一致(包括大小写、通配符)?











