nginx代理https后端证书验证失败,本质是其作为客户端校验失败,主因有三:证书不可信、域名不匹配、私钥与证书不匹配;须严格配置proxy_ssl_verify on、proxy_ssl_server_name on、proxy_ssl_name及proxy_ssl_trusted_certificate四项指令。

解决 Nginx 代理后端时的 SSL 证书链验证失败,关键不是“补全后端证书链”,而是让 Nginx 正确验证它——因为 Nginx 在 proxy_pass https:// 场景下是 HTTPS 客户端,必须能用可信根证书去校验后端返回的整条证书链。
确认失败根源:不是链不全,而是验证没走通
证书链不完整本身不会导致 Nginx 报“超时”或“handshake failed”,只会触发明确的校验错误,比如:
SSL_do_handshake() failed: SSL certificate problem: unable to get local issuer certificatessl routines::certificate verify failed
这类报错说明 Nginx 尝试验证后端证书,但找不到能签发它的可信根。常见原因有:
- 后端用了自签名证书或内网 CA 签发的证书,但 Nginx 没加载对应根证书
-
proxy_ssl_trusted_certificate路径写错、文件为空、或内容不是 PEM 格式根证书 - 启用了
proxy_ssl_verify on却没配proxy_ssl_trusted_certificate,Nginx 等待信任锚却一直等不到
必须配置的四项核心指令
缺一不可,尤其在生产环境:
-
proxy_ssl_verify on;—— 开启对后端证书的主动验证(默认是 off) -
proxy_ssl_trusted_certificate /etc/nginx/ssl/internal-ca.crt;—— 指向包含可信根证书(及可选中间证书)的 PEM 文件 -
proxy_ssl_server_name on;—— 启用 TLS SNI 扩展,让后端知道该返回哪张证书 -
proxy_ssl_name "api.example.com";—— 显式指定 SNI 域名,必须与后端证书的 SAN 或 CN 匹配
注意:proxy_ssl_name 不是可选的——如果 proxy_pass 写的是 IP 或变量,Nginx 无法自动提取域名,必须手动指定。
验证与调试方法(不重启 Nginx)
快速确认后端证书是否可被正确识别和验证:
- 在 Nginx 服务器上执行:
openssl s_client -connect backend-ip:443 -servername api.example.com -showcerts
观察输出中的subject=和X509v3 Subject Alternative Name:是否含目标域名 - 检查
proxy_ssl_trusted_certificate文件是否真含根证书:openssl x509 -in /etc/nginx/ssl/internal-ca.crt -text -noout | grep "Subject:" - 临时开启 debug 日志:
error_log /var/log/nginx/error.log debug;
然后看日志中是否有SSL certificate verify ok或具体失败原因
常见误操作与规避方式
这些看似合理的行为,实际会直接导致验证失败:
- 把
ssl_certificate(用于 Nginx 自身 HTTPS 服务端)和proxy_ssl_trusted_certificate(用于代理客户端验证)混淆使用 - 在
proxy_ssl_trusted_certificate中放入了后端的域名证书或私钥——只应放根 CA 和中间 CA 的公钥证书 - 用
upstream块定义后端时只写server 10.0.0.5;,没带端口和协议,导致proxy_ssl_name失效 - 证书文件权限设为 root 且 Nginx worker 进程无读取权限(如
nginx:root用户运行时,文件需对 nginx 用户可读)











