浏览器弹出红色警告提示证书不受信任,用户无法访问网站,但网站本身服务还在运行。出现这种情况大多不是服务器宕机,而是证书配置出错。不用着急重新购买证书,优先定位故障原因。
最常见的情况就是自签名证书。使用openssl自行生成密钥和证书,没有经过可信CA机构签名,浏览器无法识别,自然判定为不安全。内网、内部测试环境用自签名证书没问题,对外提供服务,必须更换CA机构签发的正规证书。
证书过期也是高频问题。CA签发证书都带有有效期,早年有效期两年,现在主流CA缩短到一年,Let‘s Encrypt证书有效期只有90天。证书到期前没有完成续期,浏览器直接拦截访问。部分服务器配置自动续期,但续期脚本异常或是定时任务没有正常执行,管理员很难察觉,只能等到用户反馈故障。

证书链不完整属于比较隐蔽的问题。从CA获取的证书不是单独一个文件,而是一套证书链:根证书、中间证书、服务器证书。根证书内置在浏览器和操作系统中,中间证书需要手动配置到服务器,浏览器才能顺着证书链路追溯到可信根证书。很多人只部署服务器证书,遗漏中间证书,浏览器无法构建完整信任链路,弹出证书不受信任提示。这个问题在安卓设备上更容易触发,安卓对证书链校验比桌面浏览器严格。
域名不匹配同样会触发证书不信任,报错文字一般提示证书和域名不匹配。给a.com申请的证书,部署到b.com服务器;或是证书只覆盖www.a.com,用户直接访问不带www的a.com,证书校验失败。通配符证书只能覆盖一级子域名,无法支持多级子域名,例如*.a.com不能用于b.c.a.com。
还有几个容易忽略的诱因。服务器系统时间错误,证书有效期校验就会出错,哪怕证书文件本身没问题;证书被CA吊销,浏览器通过OCSP或者CRL检测到之后拦截;客户端设备系统版本老旧,内置根证书库没有更新,无法识别新的根CA。
排查优先借助浏览器查看详情。Chrome点击地址栏锁形图标,再点击证书选项,可以查看颁发机构、有效期、证书链。证书链缺失,或是有效期已经截止,故障原因就明确了。Firefox、Safari操作路径类似,只是入口位置不一样。
命令行工具排查更直接。Linux或者macOS终端执行命令 openssl s_client -connect 你的域名:443 -servername 你的域名,输出内容包含证书链、有效期、颁发者。重点查看Verify return code,返回0代表校验通过;非0数值会附带具体失败原因。Certificate chain部分可以查看证书数量,正常包含服务器证书加一到两张中间证书。
对应处理方案。自签名证书两种处理方式:更换正规CA证书;或者把自签名根证书导入所有客户端信任库,后者仅适合内部服务。证书过期,执行续期或者重新申请证书,Let’s Encrypt可以使用certbot单条命令完成续期。证书链不完整,把中间证书和服务器证书按顺序合并成文件重新配置。Nginx配置中ssl_certificate指向的文件需要同时存放服务器证书和中间证书,顺序上服务器证书在前,中间证书在后。Apache配置区分开,SSLCertificateFile填写服务器证书,SSLCertificateChainFile填写中间证书。
域名不匹配,重新申请覆盖对应域名的证书,或是选用通配符证书覆盖全部子域名。系统时间错误,执行NTP时间同步,使用ntpdate或是timedatectl命令。
有个坑需要单独留意:证书和私钥不匹配。更换新证书,但私钥依旧使用旧文件,服务器启动可能不会报错,但HTTPS握手失败。可以执行两条命令对比校验:openssl x509 -noout -modulus -in 证书文件 | openssl md5 和 openssl rsa -noout -modulus -in 私钥文件 | openssl md5,两个输出哈希值一致才代表证书私钥配套。
推荐由外到内的排查顺序:先看浏览器报错内容,再用openssl工具校验证书链与有效期,接着检查服务器配置内证书、私钥文件路径,最后核对系统时间和CA信任库。绝大多数故障在前两步就能定位。证书不受信任不算复杂故障,只是细节很多,任意环节遗漏就报错。保证证书链完整、域名匹配、按时续期,这三点做好,可以解决九成以上相关问题。