Nginx证书链不完整是导致安卓、curl、Java等客户端报证书错误的最常见原因,需确保ssl_certificate文件包含域名证书和中间证书两段PEM内容,且openssl s_client验证显示至少两个subject/issuer。

直接看 Nginx 配置里的 ssl_certificate 文件内容,确认它是否包含至少两段证书——你的域名证书 + 中间证书。只有一段,就是链不完整,这是导致部分客户端(尤其是安卓、curl、Java 程序)报“不安全”或“CERTIFICATE_VERIFY_FAILED”的最常见原因。
查证书文件本身是否含完整链
打开你配置中 ssl_certificate 指向的 PEM 文件(比如 /etc/nginx/ssl/example.com.pem),用文本编辑器或命令行查看:
- 执行
grep "BEGIN CERTIFICATE" /path/to/your.crt | wc -l,结果应 ≥ 2 - 手动检查:文件必须以
-----BEGIN CERTIFICATE-----开头,且至少出现两次,中间不能有空行 - 第一段是你自己的域名证书,第二段必须是中间证书(CA Bundle),不能是根证书
- 如果只有 1 段,说明漏了中间证书——去证书提供商下载包里找
xxx_bundle.crt或fullchain.pem,把它追加到域名证书后面
用 OpenSSL 模拟客户端握手验证
在服务器上运行以下命令,真实模拟客户端接收证书链的过程:
openssl s_client -connect example.com:443 -showcerts 2>/dev/null | grep "subject\|issuer"- 正常输出应显示至少两个证书的
subject=(你的域名)和issuer=(中间 CA) - 若只看到一个
subject=,说明 Nginx 没发中间证书,链断裂 - 补充验证:
openssl s_client -connect example.com:443 -servername example.com,观察最后是否提示Verify return code: 0 (ok)
区分不同客户端的敏感度表现
不是所有客户端都会报错,但差异正暴露链问题:
- Chrome / Safari 桌面版有时能“兜底”缓存中间证书,表面正常;但安卓 7.0+、旧版 curl、Postman、Java HttpClient 会直接失败
- 报错典型提示:
NET::ERR_CERT_AUTHORITY_INVALID(安卓)、unable to get local issuer certificate(curl)、PKIX path building failed(Java) - 这些都不是配置语法错误,而是服务端没发全链——Nginx 的责任,不是浏览器或系统的问题
排除 ssl_trusted_certificate 的干扰
这个指令常被误用,但它对修复“不安全”警告完全无效:
-
ssl_trusted_certificate只用于验证客户端证书(mTLS)或 OCSP 响应签名,不参与向浏览器发送的服务端证书链 - 即使把它设成 fullchain.pem,只要
ssl_certificate文件里没含中间证书,浏览器照样收不到完整链 - 真正要改的只有
ssl_certificate文件内容和路径,其他 SSL 相关指令(如协议版本、加密套件)不影响链完整性


















