Nginx未发送完整证书链导致Java/Go客户端报x509错误,需用openssl s_client验证输出至少两段subject(域名证书+中间证书),确保fullchain.pem按序拼接、不含根证书且无空行,并确认配置生效。

这个问题本质是 Java 或 Go 客户端严格校验 TLS 证书链,而 Nginx 没有把中间证书发全——它们不像浏览器那样会自动补链,直接报 x509: certificate signed by unknown authority。排查重点不是客户端代码,而是确认 Nginx 实际发出去的证书是否完整、顺序是否正确、有没有混入根证书。
用 OpenSSL 直接看 Nginx 发了什么
在 Nginx 服务器上运行:
openssl s_client -connect your-domain.com:443 -servername your-domain.com -showcerts 2>/dev/null | grep "subject="
观察输出:
- 正常应有至少两行:第一行含 CN=your-domain.com(你的域名证书),第二行含 CN=Let's Encrypt R3 或类似中间 CA 名称
- 如果只有一行,或第二行是
CN=ISRG Root X1(根证书),说明链缺失、顺序错,或误把根证书拼进去了
检查 fullchain.pem 文件内容是否合规
Nginx 的 ssl_certificate 必须指向一个手动拼好的 PEM 文件,不能只用 cert.pem:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 执行
cat /path/to/fullchain.pem,确认有且仅有两个(或多个)BEGIN CERTIFICATE块 - 第一块 Subject 必须是你自己的域名;第二块起必须是中间证书(如 R3、E1、DigiCert TLS RSA SHA256 2020 CA1),不能出现 ISRG Root X1、DST Root CA X3 等根证书
- 两段之间不能有空行,也不能混入私钥、注释、Windows 换行符或乱码
确认 Nginx 配置真正生效且没被缓存干扰
改完配置 reload 后,别信“reload 成功”就完事:
- 重跑上面的
openssl s_client命令,确保输出已更新为两段证书 - 用
curl -v https://your-domain.com 2>&1 | grep "subject:"查看实际握手返回的 subject,和 OpenSSL 输出比对 - 如果是多节点或用了 CDN/WAF,确认所有入口都已更新证书文件并重载;iOS/Android 设备可能缓存旧链,可临时用 curl 直连 IP + 端口验证
Java/Go 不会自动补链,所以别依赖浏览器表现
浏览器能打开 ≠ Java/Go 能调通:
- Chrome、Safari 有内置补链机制,常掩盖问题;但 Java 的
HttpsURLConnection、Go 的默认http.Client完全不补 - 错误不是出在客户端加信任库(如 Java 的
keytool导入),而是服务端本该一次发全——这是标准 TLS 行为,也是 Let’s Encrypt 官方文档明确要求的 - 如果你正在用自签名或内网 CA 证书,那另当别论;但只要用的是 Let’s Encrypt、DigiCert、Sectigo 等公有 CA,就必须让 Nginx 发出完整中间链

















