NJS无法直接解析TLS证书,需通过外部健康服务预计算效期并提供HTTP接口,NJS用ngx.fetch()获取状态,再经map指令映射至不同upstream实现分级路由。

NJS 本身无法直接读取或解析 TLS 证书文件(如 PEM),也不能在运行时调用 OpenSSL 命令或访问证书元数据(如 notAfter)。因此,不能直接通过 NJS 获取证书剩余有效期并据此决策路由。但你可以构建一个“证书效期感知型路由策略”,其核心是:将证书生命周期管理与 Nginx 路由控制解耦,由外部系统负责探测、计算和注入状态,NJS 仅做轻量级判断与分发。
证书效期状态需由外部服务预计算并暴露为可访问端点
你必须部署一个独立的证书健康检查服务(例如用 Node.js + node-forge 或 Python + cryptography 编写),定期扫描所有站点证书,计算剩余天数,并提供 HTTP 接口返回结构化结果。例如:
-
接口地址:
http://127.0.0.1:8090/cert-status?domain=site-a.com -
响应示例:
{"domain":"site-a.com","expires_in":28,"status":"warn"}("warn"表示剩余 ≤30 天;"critical"表示 ≤7 天) - 该服务应支持缓存(如 Redis),避免每次请求都解析证书,同时设置合理 TTL(如 5 分钟)
用 NJS 主动探测并映射效期状态到变量
在 Nginx 的 http 块中引入 NJS 脚本,利用 ngx.fetch() 向上述健康服务发起异步查询,并将结果映射为可用于条件判断的变量:
- 脚本中定义函数
getCertStatus(domain),调用ngx.fetch()并解析 JSON 响应 - 使用
ngx.var将状态写入自定义变量(如$cert_status或$cert_days_left) - 注意:NJS 中的
ngx.fetch()是非阻塞的,需配合await和 async 函数,在access_by_lua_block或js_access阶段使用
结合 map 指令与 proxy_pass 实现分级路由
不依赖 if(易出错),而是用 map 将证书状态变量转为 upstream 名称,再由 proxy_pass 动态指向不同后端集群:
- 定义两个 upstream:一个用于常规流量(
upstream backend_prod),另一个用于证书临期降级(upstream backend_cert_warn,可返回维护页或备用 CDN) - 用
map $cert_status $target_upstream建立映射:default backend_prod;,"warn" backend_cert_warn;,"critical" backend_cert_warn; - 最终
proxy_pass http://$target_upstream;即完成基于效期的自动分流
配套运维闭环:确保状态实时可信
单靠 NJS 探测不够健壮,需三重保障:
- 证书更新后,触发 Webhook 通知健康服务立即刷新对应域名缓存
- NJS 中对
ngx.fetch()设置超时(timeout: 1000)和失败兜底(如设$cert_status = "unknown",默认走主链路) - 在 Nginx 日志中记录
$cert_status和$cert_days_left,便于审计与告警联动



















