域名开启 HTTPS 后,免费证书 90 天就过期,每两个月手动申请 + 部署到云主机和七牛 CDN 实在折磨。本文记录用 acme.sh + 极空间 Docker 搭一套自动续期方案的实践:七牛做到全自动,虚拟主机做到「一张证书 + 提醒」。
背景
要保护的域名:
- 博客主域 + www:部署在西部数码云峰 A 型虚拟主机
- 两个 CDN 子域:部署在七牛云
第一个关键认知:虚拟主机 ≠ 云服务器。云峰 A 型是虚拟空间,没有 SSH、不能装软件、也碰不到 nginx 配置,证书只能在西部数码控制面板的「SSL 部署」里管理。所以「在主机上装 acme.sh + reload nginx」那一套对它完全无效。
于是方案拆成两块:
- 七牛两个域名 → acme.sh 全自动部署
- 西部数码博客 → acme.sh 签发 + 企业微信提醒,手动上传「托管证书」(这是虚拟主机 + 免费前提下的上限)
签发中心放在极空间 NAS(常开、已跑 Docker),而不是 Mac(合盖就断)或虚拟主机(装不了)。
极空间部署 acme.sh 容器
docker-compose.yml(路径前缀按你极空间实际,可从已有容器的 compose 里抄):
1 | services: |
数据目录挂到容器 /acme.sh,配置和证书才能持久化(否则容器重建就没了)。
签发证书
进容器终端,用 DNSPod 的 DNS 验证签一张泛域名证书(覆盖主域 + 所有子域):
1 | export Tencent_SecretId="AKIDxxx" |
DNSPod 密钥在腾讯云「访问管理 CAM → API 密钥管理」获取,export 一次后 acme.sh 会存进账户配置,之后续期自动复用。
七牛自动部署(踩坑点)
初版想用同一张证书 deploy 到 img 和 image 两个 CDN,结果只有 img 生效。
原因:acme.sh 的 qiniu deploy-hook 会把 QINIU_CDN_DOMAIN 持久化存进证书的 conf 文件,一张证书只能存一个 CDN 域名。两次 deploy 用的是同一张证书,第二次的 image 被第一次保存的 img 覆盖了。
解法:两个 CDN 域名各签一张独立证书,各自配 deploy-hook:
1 | acme.sh --issue --dns dns_tencent -d img.log1992.cn |
配置后,这两张证书每次续期都会自动重新部署到对应七牛域名,无需干预。
博客证书 + 企业微信提醒
博客那张泛域名证书负责输出文件 + 续期提醒。先建输出目录(acme.sh 不会自动建父目录):
1 | mkdir -p /acme.sh/out |
把通知脚本挂到续期后执行:
1 | acme.sh --install-cert -d log1992.cn \ |
my-deploy.sh(只发企业微信提醒,七牛已交给各自证书的 hook):
1 | !/bin/sh |
install-cert带reloadcmd,首次安装就会立即触发一次,所以第一次执行就会收到通知——这是正常的,说明 reloadcmd 生效、通知链路通了。
西部数码虚拟主机(半自动)
虚拟主机的自动部署机制:账户名下只要有覆盖该域名的证书(自签或托管),系统就自动部署。
收到提醒后:
- 极空间文件管理 →
docker/acme/out/→ 复制blog.fullchain.pem和blog.key内容 - 西部数码 → SSL 证书管理 →「上传托管证书」→ 分别粘贴证书和私钥
- 系统自动部署到主域 + www(泛域名证书一张覆盖两个域名)
注意:西部数码开放的 SSL API 只能「买卖证书」,没有上传托管证书的接口,所以虚拟主机这块在免费前提下没法做到全自动。
运行机制
- 检测:容器 cron 每天 1 次
- 续期:证书 90 天有效,到期前 30 天自动续 ≈ 每 60 天一次
- 每 60 天收一次企业微信提醒,手动上传一次西部数码;七牛两个域名全程自动
踩坑小结
- 企业微信 webhook 的 key 是 UUID,少一个字符就静默失败(脚本里
>/dev/null把错误吞了,排查时先把重定向去掉看响应) install-cert的--key-file/--fullchain-file父目录不会自动创建,要先mkdir- acme.sh 的 deploy-hook 一张证书只能绑一个部署目标,多个目标要分多张证书
- 虚拟主机没有 SSH,别想着装 acme.sh;它的 SSL 只能走控制面板或购买证书