记一次 acme.sh 证书自动同步腾讯云 CDN 的踩坑
记一次 acme.sh 证书自动同步腾讯云 CDN 的踩坑
我的博客 nnnnzs.cn 用的是 acme.sh 自动申请泛域名 SSL 证书,服务器上 Nginx 配好证书后,每次续签自动 reload 就完事了。
但有个问题一直没解决:腾讯云 CDN 上的证书没法自动同步。
说人话就是——服务器上的证书自动续签了,CDN 那边的证书还是旧的,得手动去控制台上传。忘了的话,CDN 的 HTTPS 就挂了。
问题在哪
acme.sh 官方提供了 deploy hook 机制,续签完证书后可以自动触发一些操作。但翻了一遍官方仓库的 deploy 列表:
- 阿里云 CDN ✅ 有
- 腾讯云 CDN ❌ 没有
就这么简单一个功能,官方仓库愣是没有。
网上搜了一圈,也没找到靠谱的现成方案。那就自己写吧。
踩坑实录
坑一:tccli 不支持 base64 编码
acme.sh 有个阿里云 CDN 的 deploy hook 参考实现,里面把证书内容做了 URL 编码再传给 API。我照着写了个腾讯云版本,也先 base64 再上传。
结果报错:
CertificateParseError - 解析失败,请检查证书是否符合标准
折腾半天才发现,腾讯云的 UploadCertificate API 直接传 PEM 原文就行,不需要 base64。
坑二:tccli 参数格式
tccli 是腾讯云的命令行工具,但它的参数传递方式比较迷。
最开始我用了 --secret-id 和 --secret-key 参数:
bash
tccli ssl UploadCertificate \
--secret-id "xxx" \
--secret-key "xxx" \
--CertificatePublicKey "$cert"
结果报错:Unknown options: --secret-id, --secret-key
原来 tccli 不支持命令行传密钥,只能通过配置文件 ~/.tccli/profiles/default 或环境变量 TENCENTCLOUD_SECRET_ID / TENCENTCLOUD_SECRET_KEY 来设置。
坑三:CDN 更新接口参数
UpdateDomainConfig 这个 API 也是踩了无数坑。
先是 ExpireTime 类型错误——传了数字 0,API 要的是字符串格式的时间。
然后是 暂不支持修改此项配置——因为多传了几个字段。腾讯云这个 API 很严格,只传必要的参数,多余的别传。
最终能用的最小配置:
json
{"Switch": "on", "CertInfo": {"CertId": "Xuh5OzCp"}}
就这两行,其他什么都不用。
坑四:泛域名证书,多 CDN 域名
我的证书是 nnnnzs.cn + *.nnnnzs.cn 的泛域名,但 CDN 上有多个域名需要更新。acme.sh 的 deploy hook 支持批量操作,所以脚本要支持多个 CDN 域名。
同时还要考虑:有些域名虽然 CDN 控制台里配了,但 DNS 并没指向 CDN。比如 www.nnnnzs.cn 之前 DNS 指向服务器直连,CDN 证书配了等于白配。这次顺手把 DNS 也切到了 CDN。
最终方案
写了一个 acme.sh 的 deploy hook,放在服务器的 ~/.acme.sh/deploy/tencent_cdn.sh。
核心流程:
证书续签 → 上传到腾讯云 SSL → 批量更新 CDN 域名 → 清理旧证书
配置方式很简单,在 ~/.acme.sh/account.conf 里加几行:
bash
TENCENTCLOUD_SECRET_ID='your_secret_id'
TENCENTCLOUD_SECRET_KEY='your_secret_key'
DEPLOY_TENCENTCDN_DOMAINS='www.nnnnzs.cn static.nnnnzs.cn'
然后执行:
bash
acme.sh --deploy -d nnnnzs.cn --deploy-hook tencent_cdn
之后每次 acme.sh 自动续签证书,就会自动把新证书同步到所有 CDN 域名。
CDN 缓存规则
既然都切 CDN 了,顺便配了 Next.js 的缓存规则。静态资源走 CDN 缓存,动态请求不缓存:
| 规则 | 路径 | 策略 |
|---|---|---|
| 兜底 | * |
缓存 30 天 |
| 动态接口 | /api, /api-remote, /auth |
不缓存 |
| Next.js SSR | /_next/data, /_next/image |
不缓存 |
| 首页 | / |
不缓存 |
最后
现在整个流程完全自动化了:acme.sh 续签 → reload Nginx → 上传证书到腾讯云 SSL → 更新 CDN 域名配置 → 清理旧证书。再也不用手动去控制台上传证书了。
折腾了一下午,但以后省心了。