问题核心是Nginx未发送中间证书,导致iOS、安卓、微信WebView等严格客户端信任失败;必须用openssl s_client验证实际发送的证书链,确认fullchain.pem含域名证书+中间证书(不含根证书)且顺序正确。

问题核心不是证书本身无效,而是 Nginx 没把中间证书一起发给客户端。iOS、安卓、微信 WebView、curl 等严格客户端不会自动补全,只认你实际发送的链;而部分电脑浏览器能本地查到中间证书,掩盖了问题。排查必须从“服务器实际发出什么”出发,不能依赖浏览器显示。
用 openssl s_client 直接看真实发送内容
这是最准、最不可绕过的一步。在 Nginx 服务器上执行:
openssl s_client -connect your-domain.com:443 -servername your-domain.com -showcerts 2>/dev/null
重点观察输出中 -----BEGIN CERTIFICATE----- 出现几次:
- 只出现 1 次 → 仅发了你的域名证书,中间证书完全缺失
- 出现 2 次 → 正常(如域名证书 + Let’s Encrypt R3)
- 出现 3 次且第三块是 CN=ISRG Root X1 或类似根证书 → 错误:混入了根证书,或顺序颠倒
再加过滤快速确认:| grep "subject="。第一行应含 CN=your-domain.com,第二行应为中间 CA 名(如 CN=Let's Encrypt R3),不能是根证书名。
检查 fullchain.pem 文件是否真正拼对
Nginx 的 ssl_certificate 必须指向一个已拼好的文件,不是 cert.pem。手动检查:
cat /path/to/fullchain.pem
确认以下几点:
- 至少有两个 -----BEGIN CERTIFICATE----- 块
- 第一块 Subject 是你的域名(如 CN=api.example.com)
- 第二块 Issuer 必须等于第一块的 Subject(签发关系成立)
- 第二块起只能是中间证书,不能是根证书(如 ISRG Root X1)
- 两段之间不能有空行,不能含私钥、注释、BOM 头或 Windows 换行符(CRLF)
常见错误:用文本编辑器打开再保存,悄悄加了 BOM 或空行;或把 root.crt 也塞进去了。
验证配置是否生效且无干扰
改完配置并执行 nginx -t && nginx -s reload 后,别信缓存:
- 重跑上面的 openssl s_client 命令,确认输出已更新为两段以上证书
- 用 SSL Labs(ssllabs.com)扫描,看 “Certificate Chain” 是否标绿,“Chain issues” 是否为 None
- 安卓用户可清 HSTS 缓存:chrome://net-internals/#hsts → 删除域名
- 若用 CDN,请确认它没缓存旧证书响应,或临时关闭 CDN 直连测试
特别注意自签名或私有 CA 场景
这类证书不被系统默认信任,但排查逻辑一样:
- fullchain.pem 必须包含你的服务证书 + 你自己的根证书(即 CA.crt)
- 顺序必须是:服务证书在前,根证书在后
- 客户端(如安卓 App 或内网浏览器)必须手动导入该根证书,并设为“受信任的根证书颁发机构”
- 证书本身需含 SAN 扩展(如 DNS:intranet.local 或 IP:10.0.1.5),否则现代浏览器直接拒绝


















