nginx代理grpc时tls验证失败,主因是其作为https客户端需严格验证服务端证书:须返回完整证书链、启用sni并精确匹配san、指定正确ca文件、确保http/2与alpn协商成功。

排查 Nginx 代理后端 gRPC 服务时的 TLS 验证失败,核心是明确:Nginx 此时是 HTTPS 客户端,必须能成功验证 gRPC 服务端返回的证书。gRPC 默认使用 HTTP/2 over TLS,对证书链、SNI、协议兼容性比普通 HTTPS 更严格,常见报错如 SSL_do_handshake() failed、certificate verify failed 或直接 502。
确认后端 gRPC 服务是否返回完整证书链
gRPC 客户端(包括 Nginx)要求服务端在 TLS 握手时一次性发送域名证书 + 所有中间证书(不含根证书)。若只发终端证书,Nginx 无法构建信任链。
- 用 OpenSSL 模拟 Nginx 连接:
openssl s_client -connect grpc.internal:443 -servername grpc.internal -showcerts - 检查输出中
BEGIN CERTIFICATE块数量:第一块应为你的 gRPC 域名证书,第二块起应为中间证书(Issuer 与下一块 Subject 匹配) - 如果只看到一块,说明 gRPC 服务(如 Envoy、Caddy、或自研 gRPC server)未配置 fullchain.pem;需将中间证书拼接到证书文件末尾并重载服务
强制启用 SNI 并精确匹配 gRPC 证书 SAN
gRPC 服务常部署在内网或共享 IP 上,依赖 SNI 区分虚拟主机。Nginx 默认不发 SNI(尤其 proxy_pass 写 IP 时),会导致后端返回默认或通配符证书,与请求域名不匹配。
- 在
location或upstream块中必须写:proxy_ssl_server_name on;proxy_ssl_name "grpc.internal"; -
proxy_ssl_name的值必须与 gRPC 证书中的 SAN(Subject Alternative Name)完全一致:大小写、是否带www.、通配符格式(如*.internal)都不能错 - 避免用 IP 地址写
proxy_pass,改用域名:proxy_pass https://grpc.internal;(而非https://10.10.10.5)
指定正确的可信 CA 文件并验证其内容
Nginx 不用系统默认信任库,必须通过 proxy_ssl_trusted_certificate 显式提供用于验证 gRPC 证书的根/中间 CA 证书(PEM 格式)。
- 路径需绝对且可读:
proxy_ssl_trusted_certificate /etc/nginx/ssl/grpc-ca-bundle.crt; - 用命令检查文件有效性:
openssl x509 -in /etc/nginx/ssl/grpc-ca-bundle.crt -text -noout | grep "Subject:"—— 应显示你信任的 CA 名称 - 文件内只能含 PEM 格式 CA 证书(以
-----BEGIN CERTIFICATE-----开头),不能含私钥、gRPC 服务证书或重复根证书 - 若 gRPC 用自签名证书,就把该自签 CA 的根证书放进去;若用内网私有 CA,就放该 CA 的根证书
检查 gRPC 是否真走 HTTPS + HTTP/2
部分 gRPC 实现(如某些 Go net/http server)默认监听 HTTP/2 over TLS,但若 Nginx 降级为 HTTP/1.1 或禁用 ALPN,握手可能静默失败。
- 确保
proxy_http_version 1.1;和proxy_set_header Upgrade $http_upgrade;等配置不干扰——它们对 gRPC 不必要,甚至有害 - Nginx 1.19+ 默认支持 ALPN,无需额外配置;但若后端只支持 h2,而 Nginx 因 TLS 参数限制协商出 http/1.1,可能被拒绝
- 临时测试可加:
proxy_ssl_protocols TLSv1.2 TLSv1.3;proxy_ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;(匹配后端支持的最小集)











