浏览器提示“证书不受信任”的根本原因是客户端未信任根证书,需三步闭环解决:1. 证书必须含SAN扩展(如IP或DNS);2. Nginx的ssl_certificate须为server.crt与CA.crt拼接的完整链;3. 根证书须手动导入系统/浏览器受信任根证书库并设为始终信任。

浏览器提示“证书不受信任”,问题不在 Nginx 是否启用了 HTTPS,而在于它是否把一条能让浏览器认得出来的信任链,完整、正确地送到了浏览器手里。核心就三点:证书本身含不含 SAN、服务端发没发全链、客户端信不信这个根。
检查证书是否包含正确的 Subject Alternative Name(SAN)
现代浏览器基本只看 SAN 字段,完全忽略 CN(Common Name)。哪怕你写了 CN=192.168.1.100,只要 SAN 里没声明这个 IP 或域名,Chrome、Edge、Safari 就会直接标“不安全”。
- 生成自签名证书时,必须用 -extfile 指定扩展配置,明确写入:
subjectAltName = IP:192.168.1.100 或 subjectAltName = DNS:dev.local - 验证命令:
openssl x509 -in server.crt -text -noout | grep -A1 "Subject Alternative Name"
输出应类似:
X509v3 Subject Alternative Name: IP Address:192.168.1.100, DNS:dev.local - 若无此字段,必须重新签发证书——改配置、重启 Nginx 都没用。
确认 Nginx 是否发送了完整且顺序正确的证书链
Nginx 只通过 ssl_certificate 这一个指令向浏览器发证书链。它不关心 ssl_trusted_certificate,那个是给 Nginx 自己当客户端时用的,和浏览器无关。
-
ssl_certificate 必须指向一个拼接好的 PEM 文件,顺序严格为:
— 第一段:你的服务证书(server.crt)
— 后续段:中间证书(如 Let’s Encrypt 的 R3),不能含根证书
两段之间不能有空行,每段以 -----BEGIN CERTIFICATE----- 开头 - 验证拼接是否有效:
openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout
应输出两个或多个证书信息 - 真实查看 Nginx 当前发了什么:
openssl s_client -connect your-domain.com:443 -showcerts
第一块必须是你域名的证书,后续是中间证书;如果只有一块,或顺序颠倒,就是链配置错误。
确保客户端已信任该证书的根颁发者
浏览器只信任操作系统或自身内置的根证书库。自签名或私有 CA 的根证书,必须手动导入到系统级“受信任的根证书颁发机构”存储区,不是点“继续访问”就能绕过的。
- Windows:双击 CA.crt → “安装证书” → 选择“本地计算机” → 存储位置选“受信任的根证书颁发机构”
- macOS:用钥匙串访问导入 → 右键证书 → “显示简介” → “信任”下拉选“始终信任”
-
Linux(Chrome/Edge):通常复用系统证书库,需运行:
sudo cp CA.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates - 导入后,务必用无痕窗口重试,避免缓存干扰判断。
排除缓存与配置加载异常
有时你以为 reload 成功了,其实 Nginx 还在用旧证书,或者客户端看到的是 CDN/代理缓存的响应。
- 用 curl -v https://your-domain.com 或 openssl s_client 直连服务器 IP 和端口,绕过所有中间层
- 检查 Nginx 是否真加载了新配置:
nginx -t 确认语法,再 ps aux | grep nginx 看主进程启动时间是否更新 - 证书文件权限要合理:证书链建议 644,私钥必须 600,否则 Nginx 可能静默降级使用旧文件或报错失败
- 如果用了 OCSP stapling,旧 OCSP 响应可能被缓存,导致新证书状态延迟生效,可临时关闭测试:
ssl_stapling off;











