解决证书链不完整问题的关键是确保ssl_certificate文件按顺序拼接域名证书和中间证书(不含根证书),而非配置ssl_trusted_certificate;后者仅用于mTLS客户端验证,不参与服务端证书链发送。

ssl_trusted_certificate 不是用来修复“客户端访问你的 Nginx 站点时提示证书链不完整”的问题——它压根不参与向客户端发送证书链的过程。如果你在 myssl.com、SSL Labs 或浏览器里看到“证书链不完整”警告,那说明 Nginx 没有把中间证书发给客户端,此时该配的是 ssl_certificate 文件内容,不是 ssl_trusted_certificate。
为什么改 ssl_trusted_certificate 不能解决证书链警告
这个指令只在两种场景下起作用:
• 启用双向 TLS(mTLS)时,用来验证客户端提交的证书是否由你信任的 CA 签发;
• 配合 ssl_client_certificate 和 ssl_verify_client on 使用。
它完全不影响 Nginx 自己对外提供的 HTTPS 服务所发送的证书链。所以,无论你把它指向 fullchain.pem 还是空文件,只要 ssl_certificate 本身没包含中间证书,客户端就收不到完整链,警告照旧。
真正要改的是 ssl_certificate 文件内容
必须确保该文件是一个拼接好的 PEM 文件,顺序严格为:
• 域名证书(server.crt)
• 中间证书(CA Bundle,如 chain.pem 或 Let’s Encrypt 的 fullchain.pem 中的后半部分)
• 不要加根证书(根证书本就不该发给客户端)
• 两段之间**不能有空行**,每段都以 -----BEGIN CERTIFICATE----- 开头,-----END CERTIFICATE----- 结尾
常见错误操作:
• 把私钥也塞进 ssl_certificate 文件里
• 用文本编辑器保存时用了 UTF-8 BOM 或自动换行符(Windows CRLF)
• 从邮箱或网页复制证书内容时带了不可见字符或格式符号
推荐生成方式:cat domain.crt chain.pem > /etc/nginx/ssl/fullchain.pem
然后在配置中写:ssl_certificate /etc/nginx/ssl/fullchain.pem;
宝塔面板用户注意:别只点“自动补全”,要确认结果
宝塔的【自动补全证书链】功能确实会下载中间证书并拼接到证书内容里,但它只对 Let’s Encrypt 类证书可靠。如果你用的是自签名、ZeroSSL、BuyPass 或私有 CA 签发的证书,这个按钮大概率失效,甚至可能把证书内容覆盖成空。
务必手动验证:
• 进入【网站】→【SSL】→【证书信息】,看是否显示“证书链完整”且无红色感叹号
• 更可靠的做法:用命令行检查 Nginx 实际加载的证书内容:openssl x509 -in /www/server/panel/vhost/cert/yourdomain.com/fullchain.pem -text -noout | grep "Subject:"
应至少输出两行 Subject:一行是你的域名,另一行是中间 CA 名称(如 “Let's Encrypt Authority X3”)
最后但最容易被忽略的一点:Nginx 不会校验自己配置的证书文件是否真能构成有效链
即使你把三段乱序的证书硬塞进一个文件,Nginx 也能启动成功,nginx -t 也不会报错。只有当客户端发起 TLS 握手时,才会暴露问题——而那时你看到的错误日志里通常只有 SSL_do_handshake() failed 这类模糊提示,不会告诉你哪一级证书缺失。
所以,每次更新证书后,必须做一次真实握手验证:openssl s_client -connect yourdomain.com:443 -showcerts 2>/dev/null | grep "s:"
输出中应该能看到至少两个 s: 行,分别对应你的域名证书和中间证书。缺一个,就是链不完整。


















