nginx必须将域名证书与中间证书按顺序拼入同一pem文件供ssl_certificate指向,不可含根证书;验证需用openssl s_client检查输出至少两段证书,安卓用户须清hsts缓存。

Nginx 不需要、也不应该把根证书(Root CA)放进 ssl_certificate 指向的文件里。
浏览器和操作系统已预装主流根证书,你主动发送根证书不仅没用,还可能引发兼容性问题(比如某些安卓版本或旧版 curl 会拒绝接受含根证书的链)。
真正要合并的是:你的域名证书 + 所有中间证书(Intermediate CA),按信任路径从近到远排列。
域名证书和中间证书怎么找?
- 域名证书:你申请后收到的
.crt或.pem文件,文件名常含域名,如example.com.crt - 中间证书:CA 提供的
.crt或.pem文件,名称通常含 “Intermediate”、“CA Bundle”、“Chain” 等字样,例如:SectigoRSADomainValidationSecureServerCA.crtDigiCertSHA2SecureServerCA.crt- Let’s Encrypt 的
R3.crt或ISRG_Root_X1.crt(注意:后者是根证书,不要加)
✅ 正确做法:只加中间证书;❌ 错误做法:把
AddTrustExternalCARoot.crt或ISRG_Root_X1.crt也塞进去。
合并命令(推荐用 cat)
cat example.com.crt intermediate.crt > fullchain.pem
如果有两级中间证书(比如先由 R3.crt 签发,再由 ISRG_Root_X1.crt 签发),只需加 R3.crt —— 因为 ISRG_Root_X1.crt 是根证书,不参与拼接。
多级中间证书时顺序必须是:
- 第一段:
example.com.crt(你自己的证书) - 第二段:直接签发它的中间证书(如
R3.crt) - 第三段:再上一级中间证书(如
ISRG_Root_X1.crt的上一级,但现实中 Let’s Encrypt 已无此级;而 Sectigo 可能有USERTrustRSAAddTrustCA.crt→SectigoRSADomainValidationSecureServerCA.crt)
⚠️ 关键:从 leaf 到 root 方向,但停在中间证书最后一级,不包含 root。
验证是否拼对了
检查段数:
grep -c "BEGIN CERTIFICATE" fullchain.pem
结果应 ≥ 2(域名证书 + 至少一个中间证书)。
打开 fullchain.pem 确认:
- 两段之间不能有空行
- 每段以
-----BEGIN CERTIFICATE-----开头、-----END CERTIFICATE-----结尾 -
没有私钥内容(私钥必须单独放在
.key文件中)
Nginx 配置要点
在 server 块中:
ssl_certificate /path/to/fullchain.pem; ssl_certificate_key /path/to/example.com.key;
-
ssl_certificate必须指向你刚拼好的fullchain.pem -
ssl_certificate_key仍指向原始私钥文件,不要合并私钥 -
ssl_trusted_certificate是可选配置,仅用于 OCSP stapling 或双向 TLS,对浏览器证书链无效,不用配也行
补充:怎么确认链真的生效了?
在服务器执行:
openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null | grep "BEGIN CERTIFICATE"
输出应至少显示两段,且第二段不是 self signed certificate。
再用 SSL Labs 测试,看到 “Chain issues: None” 就说明成功了。











