这个坑值得记一笔。网关要求双向 TLS,客户端带 client.crt 与 client.key 请求报 SSL: unable to verify the first certificate,用 openssl s_client 看服务端只下发了叶子证书,没有中级 CA。

刚开始盯着「证书链拼接顺序写反」,折腾了半个多小时,排掉了。

真正麻烦的地方在于,几个原因的现象几乎一样。服务端没有下发中级证书,链不完整;客户端没配 CA bundle 或 bundle 里缺根证书;证书与私钥不是一对。

上来先把服务端证书链打印出来看

openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts < NUL

接着核对证书与私钥是否匹配

openssl x509 -noout -modulus -in client.crt | openssl md5; openssl rsa -noout -modulus -in client.key | openssl md5

随后把中级证书拼进服务端证书文件后重启

cat server.crt intermediate.crt > fullchain.crt && nginx -s reload

等前面都确认过,再用完整链再发起一次请求

curl -s -o /dev/null -w '%{http_code}\n' --cert client.crt --key client.key --cacert ca.crt https://api.example.com/health

那几天正好在做别的变更,先把时间线对齐才敢动手。

怎么算真的好了,看的是同一批现象。握手成功返回 200,openssl 输出里能看到叶子加中级两张证书,客户端不再报 unable to verify。

缺中级证书在浏览器里经常被自动补链掩盖,服务间调用没有这个兜底,部署时就把 fullchain 一起发。同一份配置在测试环境跑通,不代表线上没事,两边的默认值经常不一样。

作者 9823189