acme.sh 泛域名证书自动化:DNS API 模式从申请到续期
以前一直用 HTTP-01 验证:临时开 80 端口、停掉占用端口的容器、申请、再恢复。服务一多这套流程就是灾难。换到 DNS-01 + acme.sh 之后,一年多没再碰过证书,本文把链路记全。
为什么是 DNS-01
三个理由:能签泛域名(*.example.com);不依赖 80/443 端口的可达性(服务在内网也能签);续期不需要任何停站动作。代价是要把 DNS 托管商的 API Token 交给脚本,Token 权限务必最小化:只给目标 Zone 的 DNS 编辑权限。
申请流程(Cloudflare 为例)
1. CF 后台建 API Token:权限选 Zone.DNS Edit,资源范围限定单个 Zone。注意 DNS 只开灰色云(DNS only)不影响 DNS-01 验证——验证走的是 TXT 记录查询,与 CDN 代理无关。
2. 装 acme.sh 并配置环境变量:
curl https://get.acme.sh | sh -s email=ops@example.com
export CF_Token="你的Token"
export CF_Zone_ID="你的ZoneID"
3. 签泛域名证书:
~/.acme.sh/acme.sh --issue --dns dns_cf \
-d example.com -d '*.example.com' \
--keylength ec-256 --server letsencrypt
4. 安装到 nginx 使用路径并挂 reload 钩子:
~/.acme.sh/acme.sh --install-cert -d example.com --ecc \
--fullchain-file /etc/nginx/ssl/example.com.pem \
--key-file /etc/nginx/ssl/example.com.key \
--reloadcmd "systemctl reload nginx"
续期与验证
acme.sh 装完自动注册 cron / systemd timer,每天检查一次,距到期 30 天内自动续期并执行 reloadcmd。验证自动化是否健康只需要两件小事:一是 ~/.acme.sh/acme.sh --list 看下次续期时间;二是给 cron 的输出接一个通知(我用 ntfy 推到手机,失败当天就能知道)。
遇到的两个小坑
ECC 与旧客户端:ec-256 证书在个别老安卓上不认。我最终用 ECC 签主站、RSA 给需要兼容老设备的子域,acme.sh 分开管即可。
泛域名不含根域:*.example.com 不覆盖 example.com 本身,申请时必须两个一起写,漏了根域就等着某天首页证书报错吧。
小结
整套配置一次性投入约半小时,之后完全免维护。证书这种东西就应该像空气一样存在——你只有在它出问题的时候才想起它,而自动化的意义就是让你永远想不起它。