实战笔记:为了不再漏掉任何一个域名到期提醒,我做了个自动化检测工具
记录如何通过 Go 语言实现多域名 SSL 证书到期自动巡检,并通过钉钉/企业微信机器人实现精准预警。 在运维工作中,有一类事故极其低级却又杀伤力巨大:SSL 证书过期。 痛点:被动挨打的“救火”模式 由于业务需要,我手里管理着大量客户的域名。每个客户购买证书的渠道各异(阿里云、腾讯云或其他厂商),证书下来后通过微信或邮件发给运维,再手动配置到服务器上。 这套流程在客户少的时候还算正常。但随着客户增多,问题出现了:证书到期时间不一,全靠人工记忆。 总会有那么一两次,因为忙碌或者交接疏忽,某个域名证书悄悄过期了。直到客户反馈 APP 无法访问、浏览器弹出红色的安全告警,我们才急忙去“救火”。这种被动的局面不仅影响专业度,也给客户带来了实际损失。 方案:主动出击的自动化巡检 为了彻底根治这个“心病”,我决定做一个自动化的域名证书检测工具。 我的设想很简单:变“人找信息”为“信息找人”。 1. 实现原理 配置简单化:将所有需要监测的域名汇总成一个 txt 文件,每行一个域名,管理起来极其方便。 核心引擎(Go):使用 Go 语言开发后端服务,利用 cron 库开启定时任务,设定每天固定时间(如凌晨 4 点)执行一次巡检。 检测逻辑:程序自动循环读取域名列表,通过 TLS 握手获取证书的有效载荷,计算当前的剩余天数。 精准预警:我设定了一个“7天阈值”。一旦发现有域名将在 7 天内过期,程序会立即将这些域名汇总,并通过企微或者钉钉送达。 2. 消息触达:为什么选择机器人? 在小程序中,邮箱属于敏感隐私资料,审核往往比较严格。为了避开这个麻烦,同时也为了让通知更具实时性,我选择了钉钉机器人和企业微信机器人。 管理员或运营人员只需将机器人的 Webhook 地址配置好,每天早上一上班,就能在手机上收到一份清晰的到期清单。 价值:买到了最宝贵的“时间” 这个功能上线后,我们最直接的收获就是**“沟通时间”**: 提前预判:有了 7 天的缓冲期,运营人员可以气定神闲地与客户沟通续费。 提前操作:运维人员有了充裕的时间更换新证书,彻底杜绝了“半夜修证书”的尴尬。 技术实现 整个域名检测分为两部分:小程序端和服务端,小程序端负责提交域名信息以及Webhook(钉钉、企微)信息。以及查看导入的域名。服务端需要存储域名以及Webhook。并在每天的固定时刻进行域名巡检,当域名证书有效期小于7天时,将发送通知给管理员。 小程序端主要是常规的信息提交,我们来看下后端的Go代码: // 域名证书检测计划任务,每天固定6点执行 func CronCertCheck() { logger.Info("启动域名证书检测计划任务") // 获取用户webhook,有webhook则进行域名检测 webhooks, err := dao.GetAllWebhook() if err != nil { logger.Error("计划任务域名证书检测加载Webhooks错误,", err) return } // 循环扫描 for _, v := range webhooks { uid := v.Uid url := v.Url ht := v.HookType // 获取单个用户的域名 dbDomains, err := dao.GetWDomainByUid(uid) if err != nil { logger.Error(uid, "计划任务域名证书检测获取域名列表错误,", err) continue } if len(dbDomains) == 0 { logger.Error(uid, "计划任务域名证书检测用户域名数量为0") continue } // 解密URL地址为WEBHOOK password := fmt.Sprintf("domain:%d:%d", uid, ht) webhook, err := cryptoutil.AesDecryptWithPassword(url, password) if err != nil { logger.Error(uid, "计划任务域名证书检测webhook解密失败,", err) continue } // 获取域名列表,需要去重,用户是可以上传重复域名的。 domains := make([]string, 0) domainMap := make(map[string]bool, 0) for _, n := range dbDomains { name := n.Name isExist := domainMap[name] if isExist { continue } domains = append(domains, name) domainMap[name] = true } // 开始批次检测,并将检测结果返回 chkResult := CheckDomainsCert(domains, nil) // 如果结果不为空,则发送webhook通知 if len(chkResult) > 0 { notifyCfg := NotifyConfig{ Type: ht, URL: webhook, RetryTimes: 3, RetryDelay: 5, } result := NotifyContent{ Title: "以下域名的SSL证书将在7天内过期:", Domains: chkResult, } go SendWebhookNotificationWithRetry(notifyCfg, result) } // 休息1秒 time.Sleep(1 * time.Second) } logger.Info("域名证书检测处理:", len(webhooks)) } 在小程序上线后,用户使用极少,我不知道具体原因,可能是不信任功能,Webhook不想暴露,域名不想暴露?我又开发了客户端工具,纯本地运行,使用Wails3开发,是图形化桌面客户端,域名导入和通知都是在本地运行。并且增加了很多功能。例如支持HTTP/3,支持系统托盘,支持开启启动,支持导入更多域名,支持更多Webhook通知,监控面板更精细等。 ...