acme.sh 自动续期 SSL 证书

  • ~3.19K 字

域名开启 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
2
3
4
5
6
7
8
9
services:
acme.sh:
image: neilpang/acme.sh:latest
container_name: acme.sh
command: daemon # daemon 模式:常驻 + 内置 cron 自动续期,必须
restart: always
network_mode: host
volumes:
- /tmp/zfsv3/nvme11/你的极空间ID/data/docker/acme:/acme.sh

数据目录挂到容器 /acme.sh,配置和证书才能持久化(否则容器重建就没了)。

签发证书

进容器终端,用 DNSPod 的 DNS 验证签一张泛域名证书(覆盖主域 + 所有子域):

1
2
3
4
5
export Tencent_SecretId="AKIDxxx"
export Tencent_SecretKey="xxx"
acme.sh --register-account -m you@example.com
acme.sh --set-default-ca --server letsencrypt
acme.sh --issue --dns dns_tencent -d log1992.cn -d '*.log1992.cn'

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
2
3
4
5
6
acme.sh --issue --dns dns_tencent -d img.log1992.cn
export QINIU_AK="你的七牛AK"; export QINIU_SK="你的七牛SK"
QINIU_CDN_DOMAIN=img.log1992.cn acme.sh --deploy -d img.log1992.cn --deploy-hook qiniu

acme.sh --issue --dns dns_tencent -d image.log1992.cn
QINIU_CDN_DOMAIN=image.log1992.cn acme.sh --deploy -d image.log1992.cn --deploy-hook qiniu

配置后,这两张证书每次续期都会自动重新部署到对应七牛域名,无需干预。

博客证书 + 企业微信提醒

博客那张泛域名证书负责输出文件 + 续期提醒。先建输出目录(acme.sh 不会自动建父目录):

1
mkdir -p /acme.sh/out

把通知脚本挂到续期后执行:

1
2
3
4
acme.sh --install-cert -d log1992.cn \
--key-file /acme.sh/out/blog.key \
--fullchain-file /acme.sh/out/blog.fullchain.pem \
--reloadcmd "sh /acme.sh/my-deploy.sh"

my-deploy.sh(只发企业微信提醒,七牛已交给各自证书的 hook):

1
2
3
4
#!/bin/sh
WECOM="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=你的BOT_KEY"
curl -sS -X POST "$WECOM" -H 'Content-Type: application/json' \
-d '{"msgtype":"text","text":{"content":"✅博客证书已续期,请去西部数码上传托管证书"}}' >/dev/null

install-certreloadcmd首次安装就会立即触发一次,所以第一次执行就会收到通知——这是正常的,说明 reloadcmd 生效、通知链路通了。

西部数码虚拟主机(半自动)

虚拟主机的自动部署机制:账户名下只要有覆盖该域名的证书(自签或托管),系统就自动部署。

收到提醒后:

  1. 极空间文件管理 → docker/acme/out/ → 复制 blog.fullchain.pemblog.key 内容
  2. 西部数码 → SSL 证书管理 →「上传托管证书」→ 分别粘贴证书和私钥
  3. 系统自动部署到主域 + 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 只能走控制面板或购买证书
赞助喵
非常感谢您的喜欢!
赞助喵
分享这一刻
让朋友们也来瞅瞅!