Homelab 域名证书自动化:acme.sh + 腾讯云 / 七牛 CDN 部署流水线
本文最后更新于:2026年11月6日 下午
背景
我的 DNS 用的是腾讯云的 DNSPod。
我的博客其实用到了 3-4 个域名,分布在多个云上:
ewhisper.cn博客站(部署在腾讯云 CDN 上)www.ewhisper.cn也是指向博客站(部署在腾讯云 CDN 上)pic-cdn.ewhisper.cn博客站的图床 CDN 域名(部署在七牛云 CDN 上)pic.ewhisper.cn博客站的图床回源域名(部署在七牛云 CDN 上,好像没用到)
📝Note:
都是历史原因。当初可能是因为方便 / 免费等原因导致了现在这样的架构。
一直规划着重构下,但是没时间搞🤣
这些域名证书的更新,手动续过一轮之后就不想再来第二轮。
一张证书要上传到两个 CDN,每个 CDN 至少两步操作,点完控制台还得等生效。四个域名一轮下来就是十六遍。
实在不想手动点了,索性做成一条流水线:acme.sh 签发,--reloadcmd 钩子自动部署,cron 每 6 小时巡检一次。
📝Notes:
本文是 homelab + 个人博客场景,域名和云资源都在个人账号下,和公司生产环境的多租户、多集群、多审批不是一回事。
整体链路
按签发、部署、验收的顺序拆,一条链路管一张覆盖 4 个域名的多 SAN 证书。
1 | |
第一步:复用 tccli 凭据做 DNS-01
acme.sh 的 dns_tencent 插件默认读环境变量,但本机已经装了 tccli,~/.tccli/default.credential 里躺着现成的 SecretId / SecretKey。
直接复用,省掉去 DNSPod 单独申请一套 API Token。
1 | |
首次签发成功后,dns_tencent 插件用到的 SecretId / SecretKey 会落进 ~/.acme.sh/account.conf,权限 600。这是 DNS API 凭据,TLS 私钥在证书自己的目录下。
第二步:一张多 SAN 证书还是四张独立证书
四个域名,有两种方案:
| 维度 | 4 张独立证书 | 1 张多 SAN 证书 |
|---|---|---|
| 单次续期消耗配额 | 4 次 | 1 次 |
| 到期时间 | 可能错开 | 天然统一 |
acme.sh --list |
4 行 | 1 行 |
| 部署脚本入参 | 循环 4 次 | 1 个 cert 路径 |
考虑到网络 IO 的时间消耗和证书管理的复杂度,最终选择签成一张多 SAN 证书的方案。CA 选 Let’s Encrypt 而不是 ZeroSSL,理由很朴素:LE 不需要邮箱注册,ZeroSSL 要。
📝Notes:
多 SAN 的代价是「一损俱损」,任何一个域名的 DNS-01 验证失败,整张证书都续不上。个人博客站里这些域名共用同一套 DNSPod 解析,风险可以接受。
第三步:腾讯 CDN 部署,重点在 Alias
--reloadcmd 调一个自写脚本,逻辑是先上传再部署。
1 | |
--Repeatable true 不去重。同一份 PEM 反复上传,每次都返回一个新的 CertificateId,返回体里的 RepeatCertId 始终为空。
「可重复上传」只是允许重复,并不做内容比对。
对策是固定 Alias(ewhisper.cn-acme),按 Alias 周期性批量清理旧证书,而不是在续期钩子里自动删旧证。后者一旦删错,CDN 上正在用的证书就没了。
InstanceIdList 的格式是「域名|计费开关」。off 表示走关闭 CDN 的 HTTPS 功能,所以得写 on。写成裸域名会直接报参数错误。
第四步:七牛的双域名双鉴权
七牛这边麻烦一些,证书管理和域名 HTTPS 配置分属两套 Host、两套鉴权。
| 用途 | Host | 鉴权方式 | 签名要点 |
|---|---|---|---|
证书上传 /sslcert |
fusion.qiniuapi.com(api.qiniu.com 亦可) |
QBox | 签名原文 path + "\n",body 不参与 |
域名 HTTPS 配置 /domain/<name>/httpsconf |
api.qiniu.com |
Qiniu | 必须带 X-Qiniu-Date(UTC,偏差 ≤30s),body 参与签名 |
混用的结果就是报错:401 或 404,而且报错信息不会告诉你签名方式用错了。
1 | |
这是我碰到的两个错误码:
- 612:域名不在该 AK 账号下,或者不是 CDN 域名。
- 404001:路由存在,但域名不归 CDN 管(比如它其实是 Kodo 域名)。
退役一个域名
Kodo 自定义源站域名 pic.ewhisper.cn 要做成自动化,这条路径卡住了。
提了 ticket 七牛工程师在 2026-11-02 确认:“该场景当前不支持通过 API 绑定或替换证书”,官方只提供控制台路径。
选项有两个:改成控制台手工维护,或者直接退役。
退役之前先我先核查了依赖:回源走的是直连空间,PicGo(配合 typora 写博客时自动上传图片到图床) 配置与博客文章 markdown 里 近 5000 处图片引用全部指向 pic-cdn,pic.ewhisper.cn 没有任何消费方。
那就退役:解绑源站域名、删除 DNS CNAME、从脚本的 DOMAINS 和 acme.sh 的 Le_Alt 里移除。
SAN 从 4 个精简到 3 个。
验收
续期成功只说明证书签下来了,部署还得自己验。
先比指纹,命令如下:
1 | |
再看续期计划。
1 | |
最后核对 key 与 cert 配对,两个公钥的 md5 必须一致。
1 | |
当前证书有效期 2026-11-01 至 2027-01-30,下次续期 2026-12-31。
一次 514:配置项开着,服务没开
搭建过程中撞上一次线上 HTTP Status Code: 514,顺手记录排查顺序。
脚本更新证书后,访问博客:ewhisper.cn和 www.ewhisper.cn, 结果都是 514.😱
浏览器打开 F12, 拿到两行判据:HTTP/1.1 514 Frequency Capped 和 X-Cache-Lookup: Return Directly。
接着对照厂商状态码文档逐项证伪:IP 黑白名单、IP 访问限频、证书操作、出口 IP、域名调度。其中「是不是自己刚改坏了」这条,用回滚旧证书、十分钟内恢复原状的方式排除掉了。
真因是两个域名的 CDN HTTPS 服务本身处于关闭状态, 第一次脚本的参数是 off: --InstanceIdList "a.ewhisper.cn|off", off 就直接关闭了 CDN HTTPS 功能。控制台重新启用,立刻恢复 200。
遗留风险
- 证书列表会持续增长。腾讯和七牛都不对证书去重,续期一次多一张。需要按固定 Alias 或名称周期性清理。
- acme.sh 装在
~/.acme.sh,依赖登录用户的 crontab。换机、换用户都要整体迁移,包括account.conf。(所以后面把这套功能塞到 k8s cronjob 里了 😝) - 密钥防泄漏。脚本目录已 git 初始化并推私有仓库,只白名单跟踪不含密钥的脚本和文档;
account.conf、*.key、*.cer、deploy.log和配置快照一律不跟踪,提交前用git grep扫一遍。
总结
- 凭据复用,不新申请 Token:省事,但是凭据权限太大了,万一泄露就完犊子了。
- 一张多 SAN 证书,不拆四张:节省网络 IO 时间;证书管理简单
- 固定 Alias 周期性清理,不在钩子里自动删旧证:比如
pic.ewhisper.cn用不到了,单独删掉即可 - 无法 API 自动化的域名,核查依赖后直接退役,而不是改成手工维护: 能省事就省事,能自动化就自动化
以上。