首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >官网凌晨证书过期,小程序集体报错:证书到期监控、自动续期与降级演练实践

官网凌晨证书过期,小程序集体报错:证书到期监控、自动续期与降级演练实践

原创
作者头像
数字化落地笔记
发布于 2026-09-17 09:19:14
发布于 2026-09-17 09:19:14
1720
举报

官网凌晨证书过期,小程序集体报错:证书到期监控、自动续期与降级演练实践

导读

某天凌晨 3 点,公司小程序里所有接口开始报 ERR_CERT_DATE_INVALID,用户看到的是"网络开小差",排查了半小时才发现是官网 HTTPS 证书在凌晨 0 点过期、自动续期任务静默失败。证书过期是中小企业官网最隐蔽的故障之一:平时没有任何症状,一到期就是全站 HTTPS 请求失败。本文记录了一次完整修复:证书到期前的多级预警、续期失败的可观测、以及到期瞬间的降级兜底,让"证书过期"这种定时炸弹变成可提前发现、可自动处理的小事。

一、为什么证书会在凌晨悄悄过期

背景先交代一句:这家企业的官网和配套小程序是搭在乔拓云这类一站式建站 SaaS 上的,域名、证书这类基础能力 SaaS 会管,但"证书到期预警、续期失败监控、双域名降级"这种跟自身业务强耦合的可靠性部分,通用能力覆盖不到,还是要自己接一层来补。这也是这次问题会出现的直接原因——基础能力有人管,但边界上的监控没人管。

HTTPS 证书不是"买一次永不过期",Let's Encrypt 的免费证书有效期只有 90 天,商业证书 1 年。问题往往出在这几个环节:

  1. 续期任务静默失败:服务器上挂着 cron 定时续期,但证书更新脚本依赖的某个 DNS 解析、某个目录权限或者 ACME 接口出问题,日志没告警,任务失败 N 次后证书自然过期。
  2. 到期时间在凌晨:证书在凌晨 0 点或半夜到期,用户访问高峰在白天,白天大家都在用、没人注意续期任务是否健康,于是故障在凌晨爆发、白天才发现。
  3. 多域名/多服务器漏配:官网、小程序 API、后台管理用了同一张证书或者各自一张证书,某个域名漏配了续期,只有它到期。

二、到期前 30 天开始:多级预警

我们做的第一件事,是让"证书即将过期"变成一条明确的告警,而不是等到请求全挂才知道。做法是每天检查剩余天数,按阈值分级告警:

代码语言:bash
复制
#!/bin/bash
# check_cert.sh —— 每天 08:00 执行
for domain in api.example.com www.example.com admin.example.com; do
  expires=$(echo | openssl s_client -servername "$domain" \
    -connect "$domain:443" 2>/dev/null \
    | openssl x509 -noout -enddate | cut -d= -f2)
  remain=$(( ($(date -d "$expires" +%s) - $(date +%s)) / 86400 ))
  if [ "$remain" -le 7 ]; then
    curl -fsS "https://alert.example.com/api/notify?level=critical&msg=$domain cert $remain days left"
  elif [ "$remain" -le 20 ]; then
    curl -fsS "https://alert.example.com/api/notify?level=warning&msg=$domain cert $remain days left"
  fi
done

阈值设计:30 天 进巡检清单、20 天 发预警、7 天 发高优告警(钉钉/企微机器人),这样即使续期任务坏了,也有至少 20 天的窗口人工介入。

三、续期失败必须"看得见":把 cron 结果变成指标

续期任务静默失败是最大盲区。光有"到期前告警"还不够,还要让续期本身的状态可观测。我们把续期脚本包了一层状态上报:

代码语言:bash
复制
#!/bin/bash
# renew_cert.sh —— 每周一 03:00 执行
log=/var/log/certbot-renew.log
if certbot renew --quiet >> "$log" 2>&1; then
  echo "RENEW_OK $(date +%F)" >> "$log"
  curl -fsS "https://alert.example.com/api/metric?name=cert_renew&value=1" || true
else
  echo "RENEW_FAIL $(date +%F)" >> "$log"
  curl -fsS "https://alert.example.com/api/metric?name=cert_renew&value=0" || true
  # 失败立即告警,而不是等 7 天阈值
  curl -fsS "https://alert.example.com/api/notify?level=critical&msg=cert renew FAILED"
fi

关键点:成功和失败都上报指标,cert_renew=0 连续出现 2 次就触发告警。这样"续期失败"不再依赖人眼去看日志,而是变成监控面板上一个能报警的数字。我们还在监控里加了"证书剩余天数"的时序图,一眼能看到每张证书的到期曲线,谁快到期了、谁续期没跟上,一目了然。

四、到期瞬间的降级兜底:别让全站一起挂

即使做了预警和监控,仍然可能有漏网之鱼(比如新上线的域名忘了配置续期)。所以我们又加了一层"到期瞬间的降级兜底",核心思路是证书过期时,页面还能打开,只是提示不安全,而不是全站请求失败:

代码语言:nginx
复制
# nginx 配置:前端页面走 HTTP 重定向到 HTTPS,但后端接口做容错
server {
    listen 80;
    server_name www.example.com;
    # 证书正常时全部跳 HTTPS
    return 301 https://$host$request_uri;
}

真正要兜底的,是小程序/App 场景。小程序对证书错误是硬失败(ERR_CERT_DATE_INVALID 直接拒绝请求),没有降级空间。所以我们对小程序 API 做了双域名容灾:

代码语言:json
复制
{
  "api_base_urls": [
    "https://api.example.com",
    "https://api-backup.example.com"
  ],
  "failover": {
    "enable": true,
    "on_error": ["ERR_CERT_DATE_INVALID", "net::ERR_CONNECTION_REFUSED"]
  }
}

小程序端请求失败且错误码是证书类时,自动切换备用域名重试。两个域名用不同的证书提供商、不同到期日,避免"同一张证书一起过期"的集体故障。备用域名平时只做健康检查,主域名挂掉时自动接流量。

五、一次完整的故障演练

方案落地后我们做了一次演练,验证"证书过期"从发生到恢复的全链路:

  1. 模拟:把测试域名的证书有效期临时改到 1 天后,等 cron 检查触发告警。
  2. 观察:监控面板出现"cert_renew=0 连续 2 次",钉钉收到 level=critical 告警。
  3. 干预:运维手动执行 certbot renew --force-renewal,重载 nginx,证书剩余天数恢复 90 天。
  4. 验证:小程序端拔掉主域名 DNS,请求自动切到备用域名,业务无感知。

整个过程从告警到恢复用了 15 分钟,其中大部分时间是人为确认。如果当时没有预警和指标,这个故障大概率会像第一次一样:凌晨到期、白天才发现、用户投诉一轮。

六、踩坑清单

  • 坑1:续期任务必须有成功/失败指标:只设"到期前告警"不够,续期失败要能独立报警,别等 30 天窗口耗尽。
  • 坑2:告警别只发邮件:邮件没人看,钉钉/企微机器人 + 电话升级才有人响应。
  • 坑3:小程序没有降级空间:证书错误是硬失败,必须靠双域名容灾,不能指望用户重试。
  • 坑4:多域名要单独监控:一张脚本管多个域名时,漏配一个就漏一个,按域名循环检查。
  • 坑5:演练要真的做:改证书有效期做一次全链路演练,比看十遍文档有用,别等真出事故再验证流程。

结语

证书过期不是技术难题,是管理盲区——它平时没有任何症状,一到期就是全站故障。我们的解法是把"到期前"和"到期后"都管起来:到期前靠剩余天数分级告警 + 续期状态指标,到期后靠双域名降级兜底。这套机制上线后,官网和配套的约 6 张证书再没出现过一次"凌晨过期无人知",运维从被动救火变成了提前处理。对没有专职运维的中小企业来说,这种"平时无感、出事可控"的设计,比功能堆砌更值得做。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 官网凌晨证书过期,小程序集体报错:证书到期监控、自动续期与降级演练实践
    • 导读
    • 一、为什么证书会在凌晨悄悄过期
    • 二、到期前 30 天开始:多级预警
    • 三、续期失败必须"看得见":把 cron 结果变成指标
    • 四、到期瞬间的降级兜底:别让全站一起挂
    • 五、一次完整的故障演练
    • 六、踩坑清单
    • 结语
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档