编程语言
CERT_HAS_EXPIRED:Node.js 报 certificate has expired
Error: certificate has expired (code: 'CERT_HAS_EXPIRED')certificate has expired(CERT_HAS_EXPIRED)的意思是:按客户端的时钟判断,Node.js 构建的证书链里有一张证书已经过了到期时间。 通常是服务器证书本身没续期;有时是服务器还在发送一张过期的中间证书,或者客户端的日期不对。
快速修复
多数情况是服务器证书没续期,续期并重载 Web 服务器即可。先查看服务器证书的日期和本机时间:
date -u
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -startdate -enddate
notAfter已经过去: 续期证书,连同完整证书链一起部署,然后重载 Web 服务器。- 站点证书没过期: 用
-showcerts检查服务器发送的每一张证书,把过期的中间证书从证书包里去掉。 - 本机时间不对: 修复客户端时间同步(systemd 的 Linux 上执行
timedatectl set-ntp true)。
原因
最常见的是服务器证书没续期,其次是证书包里有过期的中间证书,再次是客户端时钟错误。
1. 服务器证书过期
- 确认: 上面的命令显示
notAfter早于现在;SSL 检测工具提示已过期。 - 修复: 续期。ACME 客户端执行
certbot renew或acme.sh --renew -d example.com,并确认有部署钩子重载 Nginx 或 Apache。续期“成功”了但还是旧证书,说明 Web 服务器没重载,或者引用的是另一份副本。阿里云、腾讯云的免费证书到期后需要重新申请并重新部署。
2. 证书包里有过期的中间证书或旧交叉签名
有些服务器在旧链路的中间证书或交叉签名证书过期后,仍然把它们发给客户端。路径构建方式不同的客户端就会失败。
- 确认:
-showcerts列出的除站点证书外,还有一张notAfter已过期。 - 修复: 按 CA 当前的中间证书重新拼接证书链(可以用证书链补全工具),去掉过期的那张。
3. 客户端时钟错误
宿主机没开时间同步的容器、从快照恢复的虚拟机、嵌入式设备,日期经常是错的。
- 确认:
date -u和真实时间差很多;访问其他 HTTPS 网站也报同样的错。 - 修复: 在宿主机开启 NTP(chrony、systemd-timesyncd),国内可以用阿里云、腾讯云提供的 NTP 服务器;容器使用宿主机时钟。
4. Node.js 根证书过旧或镜像地址过时
很老的 Node.js 版本内置的根证书列表里还有、或者依赖已过期的根证书。已停用的旧镜像域名、旧 API 域名也可能出示过期证书。
- 修复: 升级到仍在维护的 Node.js LTS 版本,更新配置里过时的地址(npm 用
npm config get registry检查)。
各环境修法
防止再次过期靠三件事:自动续期、续期后自动重载、手动上传的证书改用托管证书。
Certbot: sudo certbot renew --deploy-hook "systemctl reload nginx";用 systemctl list-timers | grep certbot 确认定时器在运行。
宝塔面板: 在站点 SSL 页面确认“自动续签”已开启,并查看续签日志;续签失败常见原因是 80 端口不通或域名解析变了。
Kubernetes: 检查 TLS Secret 里的证书和 cert-manager 状态,见 cert-manager 证书一直不 Ready。
云负载均衡和 CDN: 手动上传的证书不会自己续期,改用云厂商的托管证书,或者用脚本自动上传。
无法升级的老客户端: 老设备或老运行时验证不了当前证书链时,只能升级,没有安全地“接受过期证书”的办法。
不要这样做
关闭校验、回拨时钟和置之不理,都会掩盖问题或把问题扩大到别处。
- 用
NODE_TLS_REJECT_UNAUTHORIZED=0绕过过期证书。 它关掉的是全部校验,不只是日期检查。 - 把系统时间往回调。 其他证书、日志、令牌校验都会跟着出问题。
- 因为“只有 Node.js 报错”就不管。 手机 App、合作方的接口调用等其他非浏览器客户端同样在失败。
常见问题
浏览器显示证书正常,Node.js 却说过期了,为什么?
浏览器可能构建出不同的证书链,比如绕开服务器仍在发送的过期交叉签名中间证书,而且它用的是自己最新的根证书库。Node.js 也可能跑在时钟错误的机器上。用 openssl s_client -showcerts 看服务器发出的链,和浏览器显示的对比。
npm install 报 CERT_HAS_EXPIRED,是镜像源的问题吗?
很可能。旧的淘宝 npm 镜像域名 registry.npm.taobao.org 已停用,它的证书在 2024 年 1 月过期,还在用这个地址的项目会报这个错。执行 npm config get registry 检查,改成 https://registry.npmmirror.com,同时检查项目里的 .npmrc 和锁文件里的地址。
怎么知道到底是哪张证书过期了?
打印服务器发出的每一张证书的日期:openssl s_client -connect host:443 -servername host -showcerts </dev/null,对每一段执行 openssl x509 -noout -subject -enddate。SSL 检测工具也会列出链中每张证书的到期时间。
怎么避免以后再出现?
用 ACME 客户端或云厂商的托管证书自动续期,续期后自动重载服务器,并从外部监控到期时间。2026 年证书最长 200 天,2027 年降到 100 天,2029 年降到 47 天,手动续期跟不上。