# CERT_HAS_EXPIRED：Node.js 报 certificate has expired

> Node.js 报 CERT_HAS_EXPIRED，说明证书链中有证书已过期，或者本机时间不对。依次检查服务器证书、中间证书、系统时钟和过时的镜像地址。

Source: https://ssl.sh/zh/errors/node-cert-has-expired/
Last updated: 2026-11-10

**`certificate has expired`（`CERT_HAS_EXPIRED`）的意思是：按客户端的时钟判断，Node.js 构建的证书链里有一张证书已经过了到期时间。** 通常是服务器证书本身没续期；有时是服务器还在发送一张过期的中间证书，或者客户端的日期不对。

## 快速修复

多数情况是服务器证书没续期，续期并重载 Web 服务器即可。先查看服务器证书的日期和本机时间：

```bash
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 检测工具](https://ssl.sh/zh/tools/ssl-checker/)提示已过期。
- **修复：** 续期。ACME 客户端执行 `certbot renew` 或 `acme.sh --renew -d example.com`，并确认有部署钩子重载 Nginx 或 Apache。续期“成功”了但还是旧证书，说明 Web 服务器没重载，或者引用的是另一份副本。阿里云、腾讯云的免费证书到期后需要重新申请并重新部署。

### 2. 证书包里有过期的中间证书或旧交叉签名

有些服务器在旧链路的中间证书或交叉签名证书过期后，仍然把它们发给客户端。路径构建方式不同的客户端就会失败。

- **确认：** `-showcerts` 列出的除站点证书外，还有一张 `notAfter` 已过期。
- **修复：** 按 CA 当前的中间证书重新拼接证书链（可以用[证书链补全工具](https://ssl.sh/zh/tools/chain-builder/)），去掉过期的那张。

### 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](https://ssl.sh/zh/errors/cert-manager-certificate-not-ready/)。

**云负载均衡和 CDN：** 手动上传的证书不会自己续期，改用云厂商的托管证书，或者用脚本自动上传。

**无法升级的老客户端：** 老设备或老运行时验证不了当前证书链时，只能升级，没有安全地“接受过期证书”的办法。

## 不要这样做

关闭校验、回拨时钟和置之不理，都会掩盖问题或把问题扩大到别处。

- **用 `NODE_TLS_REJECT_UNAUTHORIZED=0` 绕过过期证书。** 它关掉的是全部校验，不只是日期检查。
- **把系统时间往回调。** 其他证书、日志、令牌校验都会跟着出问题。
- **因为“只有 Node.js 报错”就不管。** 手机 App、合作方的接口调用等其他非浏览器客户端同样在失败。
