Web 服务器
安装中间证书,修复证书链不完整
安装中间证书,就是让服务器在站点证书后面按顺序发送签发它的中间证书。证书链完整后,curl、Java、手机 App、微信小程序这类不会自动补全中间证书的客户端也能正常连接。方法适用于任意 CA,以及 Nginx、Apache 2.4.8+、HAProxy、Tomcat、Node.js 和 IIS。
前提条件
需要站点证书、私钥和服务器的 Shell 权限。
- 已安装的站点证书(
example.com.crt或cert.pem)和私钥。 - 一台能上网的机器上装有 OpenSSL 1.1.1 或 3.x。
- IIS 需要管理员 PowerShell。
第一步:查看服务器当前发送的证书
用 openssl 列出服务器实际发送的证书,输出里只有深度 0 一条就是缺中间证书:
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | grep -E '^ *[0-9] s:|^ *i:'
SSL 证书检查 遇到这种情况会提示“证书链不完整”。
第二步:拿到正确的中间证书
优先用 CA 或 ACME 客户端给的证书包:Certbot 的 fullchain.pem 和 chain.pem、acme.sh 的 fullchain.cer、商业 CA 的 CA bundle,或云厂商下载包里的证书链文件。只有站点证书时,读出 CA Issuers 地址下载签发者证书:
openssl x509 -in example.com.crt -noout -ext authorityInfoAccess
curl -fsSL -o intermediate.der "http://ca-issuers.example.net/intermediate.crt"
openssl x509 -inform DER -in intermediate.der -out intermediate.pem 2>/dev/null || cp intermediate.der intermediate.pem
把 URL 换成第一条命令输出的地址。把证书粘贴到 证书链生成器 也能自动完成这一步。
第三步:按正确顺序合成完整证书链
站点证书在前,后面依次是中间证书,每张都由下一张签发:
cat example.com.crt intermediate.pem > fullchain.pem
openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout
输出里每张证书的 issuer 必须等于下一张的 subject。再用系统信任存储验证:
openssl verify -untrusted intermediate.pem example.com.crt
第四步:配置服务器
多数服务器直接读取完整证书链文件,Tomcat 和 IIS 例外。
Nginx:ssl_certificate 指向完整证书链。
ssl_certificate /etc/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/ssl/example.com/example.com.key;
Apache 2.4.8+:SSLCertificateFile 使用完整证书链,SSLCertificateChainFile 已经过时。
SSLCertificateFile /etc/ssl/example.com/fullchain.pem
SSLCertificateKeyFile /etc/ssl/example.com/example.com.key
HAProxy:一个 PEM 同时包含完整证书链和私钥,cat fullchain.pem example.com.key > /etc/haproxy/certs/example.com.pem。
Tomcat:certificateChainFile 只放中间证书(intermediate.pem),不放站点证书。
Node.js:cert: fs.readFileSync('fullchain.pem')。
IIS:把中间证书导入本机的中级证书颁发机构存储,IIS 会自动发送:
Import-Certificate -FilePath C:\certs\intermediate.cer -CertStoreLocation Cert:\LocalMachine\CA
改完后重载服务(sudo nginx -t && sudo systemctl reload nginx、sudo systemctl reload apache2 等)。宝塔面板里把完整证书链整段粘贴到“证书(PEM 格式)”框即可。
验证
配置正确时,服务器同时发送站点证书和中间证书,检查结果不再提示“证书链不完整”。重载后用 SSL 证书检查 从外部确认,或在终端运行:
curl ssl.sh/example.com
本地的 curl 使用自己的信任存储、不会自动补全中间证书,是很严格的测试:
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com
自动续期
CA 会轮换中间证书,Let's Encrypt 这些年也多次更换证书层级,手工拼好的证书链会随之过时。ACME 客户端每次续期都会给出当前的证书链:服务器直接引用 Certbot 的 fullchain.pem、acme.sh 的 --fullchain-file 或 lego 打包好的 .crt,不要引用单独保存的中间证书。商业证书和云厂商证书每次重新签发后都要重新下载整个证书包。证书最长 200 天(2029 年 3 月 15 日起 47 天),能用 ACME 就自动化,并把域名加到 ssl.sh 监控(开发中),证书链不完整时会提醒。
常见问题排查
- curl: (60) SSL certificate problem: unable to get local issuer certificate:中间证书仍然缺失,见 curl 60 错误。
- Java 报 PKIX path building failed:见 PKIX path building failed。
- Node.js 报 UNABLE_TO_VERIFY_LEAF_SIGNATURE:见 UNABLE_TO_VERIFY_LEAF_SIGNATURE。
- Firefox 报 SEC_ERROR_UNKNOWN_ISSUER:见 SEC_ERROR_UNKNOWN_ISSUER。
- Nginx 报 key values mismatch 无法启动:中间证书放在了站点证书前面,见 nginx key values mismatch。
常见问题
阿里云、腾讯云下载的证书包含中间证书吗?
Nginx 格式的 .pem 或 .crt 文件通常已经包含站点证书和中间证书,直接用作 ssl_certificate 即可。Apache 格式一般把站点证书和证书链分成两个文件,Apache 2.4.8 及以上可以把两个文件按“站点证书在前”合并后用作 SSLCertificateFile。具体文件名以下载包为准。
证书链里要不要放根证书?
不用。客户端的信任存储里已经有根证书,服务器发送的根证书不参与信任判断,只会让每次握手多传数据。
为什么 Chrome 能打开,curl 和小程序报错?
桌面浏览器能通过 AIA 地址自动补全缺失的中间证书,或复用访问其他网站时缓存的中间证书;curl、Java、大多数手机 App 和微信小程序不会,于是报颁发者未知。见 缺少中间证书。