一、先看清是哪种报错
| 浏览器提示 | 原因 |
|---|---|
NET::ERR_CERT_DATE_INVALID | 证书过期,或本机时间不对 |
NET::ERR_CERT_COMMON_NAME_INVALID | 证书域名与访问域名不匹配 |
NET::ERR_CERT_AUTHORITY_INVALID | 自签名证书,或中间证书缺失导致链不完整 |
NET::ERR_CERT_REVOKED | 证书已被吊销 |
SSL_ERROR_NO_CYPHER_OVERLAP | 协议/加密套件不兼容(老客户端或配置过严) |
先按提示定位,不要上来就重装证书。
二、域名不匹配:最常见
证书只对「证书里的名字」有效。要区分两种:
- 单域名:只认
www.it586.cn,访问裸域it586.cn就会报名称不匹配。 - 通配符(
*.it586.cn):覆盖一级子域,但不覆盖it586.cn本身,也不覆盖a.b.it586.cn。 - 多域名(SAN):一张证书列多个名字,适合主站 + API 子域。
所以「www 和裸域都要用」时,正确做法是:证书里同时包含两个名字(SAN),或把裸域 301 跳到 www。只配 www 却在 DNS 里让裸域也能解析,用户就会看到证书错误——这也是「裸域 301」必须先确认证书覆盖范围的原因。
三、链不完整:只有服务器能看出来
浏览器有时能「自动补齐」中间证书,所以你在 Chrome 里看着正常,用 curl 或 Java 客户端却报 unable to find valid certification path。原因是服务器只下发了站点证书,没发中间证书。
检查命令:
openssl s_client -connect www.it586.cn:443 -servername www.it586.cn -showcerts
看输出里有几张证书:正常应是「站点证书 + 中间证书」,根证书不需要下发。修复方法是在 Nginx 的 ssl_certificate 文件里,把站点证书和中间证书按顺序拼接(站点在前):
cat site.crt intermediate.crt > fullchain.crt
顺序反了同样会报错,这是配置时最容易搞错的一步。
四、过期与自动续期
免费证书(Let's Encrypt)有效期 90 天,忘了续就整站报错。建议:
# 手动续期并重载
certbot renew --dry-run # 先演练
certbot renew
nginx -s reload
用 certbot --nginx 安装的通常已带 systemd timer 自动续期,检查 systemctl list-timers | grep certbot 确认。监控层面加一条「证书剩余天数 < 15 天告警」,比事后救火靠谱。
续期后一定要 reload,不是 restart——reload 不中断连接。
五、配置里的其它坑
- HTTP/2 与 SNI:一个 IP 上多个站点时,客户端必须发 SNI,老客户端(XP、老 Java)不发就会拿到默认站点的证书。
- HSTS 别乱开:一旦下发
Strict-Transport-Security,浏览器在有效期内强制 HTTPS,证书出问题用户连「继续访问」都点不了。首次上线建议先用短max-age。 - 混合内容:页面是 HTTPS,但里面加载了
http://的图片/脚本,浏览器会拦截。检查所有资源引用与 CDN 地址。 - 证书与私钥不匹配:报
key values mismatch,用openssl x509 -noout -modulus与openssl rsa -noout -modulus比对两个值是否一致。
六、自签名证书的正确用法
内网、测试环境用自签名没问题,但要让客户端信任:把自签 CA 证书导入系统/浏览器的信任库,而不是每次点「继续访问」。生产环境对外服务不要用自签名。
七、快速自检清单
- 证书是否过期(看
Not After)。 - 证书里的域名是否覆盖当前访问的域名(含 www / 裸域)。
- 是否下发了完整中间证书。
- 私钥与证书是否配对。
- 本机时间是否准确。
- 是否有 HTTP 资源混入。
需要快速看某域名的解析与响应状态,用 域名/IP 检测;想确认跳转链是否正确(http → https → www),看返回的状态码即可,含义参考 HTTP 状态码详解。
小结
证书问题先看报错类型:过期查时间与续期,名称不匹配查 SAN 与裸域,不受信任查中间证书。配好后用 openssl s_client 验证链,再加一条到期告警。