关键在于证书链文件必须严格按“终端证书→中间证书”顺序拼接且不含根证书,Nginx仅原样发送该PEM文件;顺序错误或混入根证书会导致安卓、curl等客户端因无法构建信任链而报错。

关键在于证书链文件的拼接顺序必须严格遵循“终端证书 → 中间证书”结构,根证书不能包含在内。Nginx 不校验 CA 来源,只认 PEM 格式和链路完整性;顺序错或混入根证书,会导致部分客户端(尤其是旧版 Android、Java 应用、curl 等)无法构建信任路径,出现证书不可信警告或连接失败。
证书链必须按层级顺序拼接
服务器证书是链的起点,中间证书是它的签发者,根证书已预装在系统中——所以 Nginx 只需提供前两者,且顺序不可颠倒:
- 第一行必须是你的域名证书(如
example.com.crt) - 紧接着追加所有中间证书,按签发关系从近到远排列(比如 Sectigo 的链:先
SectigoRSADomainValidationSecureServerCA.crt,再USERTrustRSAAddTrustCA.crt) - 根证书(如
RootCA.crt)绝对不要加入该文件;它属于信任锚点,由客户端自行匹配
不同 CA 的典型合并方式
各机构打包习惯不同,但逻辑一致:找对“叶子证书”和“中间证书”,手动合并即可:
-
Let’s Encrypt:直接用
fullchain.pem(它已是cert.pem + chain.pem合并结果) -
DigiCert / Sectigo:通常提供多个 .crt 文件,需确认哪个是域名证书(常含域名名),哪个是中间证书(名中带 “CA”、“Intermediate” 或机构名),然后执行:
cat example.com.crt DigiCertCA.crt > bundle.pem - 私有 CA 或 Vault 签发:返回的证书往往不含中间链,需额外调用 API 或从 CA 存储中获取对应中间证书补全
验证链是否完整有效
配置后别急着 reload,先本地验证链结构是否正确:
- 用 OpenSSL 检查链是否可解析:
openssl crl2pkcs7 -nocrl -certfile bundle.pem | openssl pkcs7 -print_certs -noout - 模拟客户端握手,看是否返回完整链:
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | grep "subject="(应看到至少两行:你的域名证书 + 中间证书) - 在线工具如 SSL Labs(ssllabs.com)能直观显示链路状态与兼容性评分
配置项与权限细节不能忽略
即使链文件正确,Nginx 加载失败也会导致降级为 HTTP 或 500 错误:
-
ssl_certificate必须指向合并后的 PEM 文件(如/etc/nginx/ssl/bundle.pem) -
ssl_certificate_key指向无密码的私钥,且权限设为600(chmod 600 server.key) - 确保私钥未加密——带密码的 key 会导致 Nginx 启动时卡住,需先解密:
openssl rsa -in server.key.enc -out server.key


















