SSL 证书链不完整,常见表现是电脑浏览器可以打开,旧版手机、接口客户端或某些小程序却提示“不受信任”“无法验证颁发者”或 TLS 握手失败。问题通常不是域名没有证书,而是服务器只发送了站点证书,没有把客户端建立信任路径所需的中间证书一并发送。
处理时应先确认真正终止 HTTPS 的节点,再检查服务器发出的证书列表、域名匹配、有效期和验证结果。不要看到浏览器地址栏有锁就直接认定证书链完整。
先理解站点证书、中间证书和根证书
| 证书层级 | 作用 | 服务器通常是否发送 |
|---|---|---|
| 站点证书 | 证明当前域名对应的公钥和证书主体,也叫叶子证书 | 必须发送 |
| 中间证书 | 把站点证书连接到受信任根证书 | 通常需要随站点证书发送 |
| 根证书 | 由操作系统、浏览器或客户端信任库预置 | 通常不需要服务器发送 |
一条完整路径通常是“站点证书 → 一个或多个中间证书 → 客户端信任的根证书”。不同客户端自带的中间证书缓存和根证书库不同,因此链缺失时可能出现“有人正常、有人报错”。
第一步:找到真正提供 HTTPS 的节点
使用 CDN、WAF、负载均衡或反向代理时,用户看到的证书通常来自边缘节点,不一定来自源站 Nginx。先沿访问链路确认 TLS 在哪里终止:
- 域名是否直接解析到当前服务器,还是指向 CDN/WAF 的 CNAME。
- 负载均衡、面板站点和源站是否分别配置了证书。
- 同一 IP 上有多个 HTTPS 站点时,SNI 是否把域名送到正确虚拟主机。
- 浏览器看到的新证书是否与刚刚修改的文件一致,避免改了源站却仍由边缘节点提供旧链。
域名、端口和反向代理的边界可参考域名解析与端口实现方法;若不确定问题处在哪一层,可按域名状态分层监测清单依次检查 DNS、连接、HTTPS 和页面。
第二步:查看服务器实际发送了哪些证书
OpenSSL 的 s_client 可以直接连接目标,并用 SNI 指定域名:
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null
重点查看 Certificate chain 和末尾的验证提示。-showcerts 展示的是服务器实际发出的证书列表,OpenSSL 官方文档明确说明它本身不是一条已经验证通过的证书链。若需要在错误时直接返回失败,可增加验证选项:
openssl s_client -connect example.com:443 -servername example.com \
-verify_hostname example.com -verify_return_error </dev/null
- 只有编号 0 的站点证书:通常说明服务器没有发送中间证书。
- unable to get local issuer certificate:客户端无法从已收到的证书构建到受信任颁发者,常见于中间证书缺失或不正确。
- hostname mismatch:访问域名不在证书允许的名称中,这不是补中间证书能解决的问题。
- certificate has expired:证书已过期,要续签并部署新证书,而不是只调整链顺序。
- 某些网络正常、某些网络异常:继续比较不同客户端、IPv4/IPv6、CDN 节点和 SNI 返回的证书,避免只测一个入口。
第三步:取得正确的 fullchain 文件
优先使用证书颁发机构或自动化客户端提供的完整链文件,常见名称包括 fullchain.pem、certificate_bundle.crt 或“证书链”。不要从不明网站下载中间证书,也不要把私钥粘贴到在线检测工具。
对于 Nginx,组合文件的顺序应当是站点证书在前,随后是中间证书。Nginx 官方文档给出的思路是把已签发的站点证书与 CA 提供的链文件按此顺序合并:
cat site.crt intermediate-bundle.crt > fullchain.pem
如果有多个中间证书,也应按从站点证书向根证书延伸的顺序排列。根证书通常已经存在于客户端信任库,不必为了“看起来完整”重复放进服务器链。
第四步:在 Nginx 中部署并验证
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/private.key;
}
ssl_certificate 指向包含站点证书和中间证书的完整链文件,ssl_certificate_key 单独指向匹配的私钥。保存后先检查配置,再平滑重载:
nginx -t
nginx -s reload
不要在未通过 nginx -t 时直接重启。链文件顺序错误、证书与私钥不匹配、文件权限不正确或路径拼写错误,都可能让配置校验失败。重载成功后,应再次从外部网络运行 OpenSSL 检查,而不是只看面板里显示“已部署”。

使用 CDN、面板或负载均衡时怎么处理
| 场景 | 应检查的位置 | 常见遗漏 |
|---|---|---|
| CDN/WAF | 边缘证书配置和回源 HTTPS 配置 | 只更新源站,边缘仍发送旧证书或缺失链 |
| 宝塔等面板 | 当前站点绑定域名、证书内容和实际 Nginx 配置 | 证书粘贴框只填了站点证书,没有填完整链 |
| 云负载均衡 | 监听器绑定的证书、SNI 规则和后端协议 | 修改了错误监听器或默认证书 |
| 多服务器 | 每个节点和每条 IPv4/IPv6 路径 | 部分节点续期成功,其他节点仍使用旧链 |
证书链修复后仍报错的排查顺序
- 确认访问域名与证书 SAN 中的名称匹配,测试时带上正确 SNI。
- 确认当前时间正确,证书未过期、尚未生效等时间问题不存在。
- 核对线上实际返回的证书指纹和序列号,确保流量已经到达修改后的节点。
- 分别测试 IPv4、IPv6、CDN 节点和备用服务器,排除配置不一致。
- 检查客户端信任库是否过旧,尤其是旧系统、Java 运行环境和嵌入式设备。
- 查看服务端和客户端 TLS 错误日志,区分链问题、协议版本、密码套件和双向证书问题。
- 续期自动化完成后增加外部验证,避免“证书文件已更新但服务未加载”。
常见问题
为什么 Chrome 正常,接口请求却失败?
浏览器可能缓存过中间证书,或者不同客户端使用不同信任库。接口客户端如果只依赖服务器本次发送的证书,更容易暴露链缺失。应修复服务器链,而不是要求每个客户端手工导入中间证书。
fullchain.pem 里需要包含私钥吗?
不需要,也不应该。fullchain 通常只包含公开的站点证书和中间证书;私钥应单独保存、严格限制读取权限,并通过 ssl_certificate_key 配置。
证书链完整就代表 HTTPS 一定安全吗?
不是。完整链只解决信任路径问题,还要检查私钥保护、域名匹配、证书有效期、协议和密码套件、HSTS、应用漏洞以及 CDN 与源站配置。SSL 基础概念可查看网站 SSL 证书指南。
总结
修复 SSL 证书链不完整,核心是确认 HTTPS 终止节点,查看服务器实际发送的证书,取得 CA 提供的正确中间证书,并按“站点证书在前、中间证书在后”的顺序部署 fullchain。修复后要从外部、带正确 SNI 再次验证,并检查所有 CDN、负载均衡和多节点入口。





暂无评论内容