acme.sh 实现证书的自动化申请与续期

引言

acme.sh 是一个完全用纯 Shell (Unix shell语言) 编写的开源脚本工具。它实现了 ACME 协议(一种用于自动化获取和管理 SSL 证书的互联网协议),充当了用户与证书颁发机构(CA)之间的“自动化中介”。

简单来说,它把原本繁琐、需要人工干预的 SSL 证书申请和部署过程,变成了一键自动化操作。它的核心作用包括:

  • 自动申请免费证书:能够自动向 Let's Encrypt、ZeroSSL 等受信任的证书颁发机构申请免费的 SSL/TLS 证书。
  • 自动化域名验证:支持 HTTP 验证和 DNS API 验证。通过对接阿里云、腾讯云、Cloudflare 等 100 多家 DNS 服务商的 API,它可以自动添加 TXT 记录来完成域名所有权验证,无需手动操作。
  • 自动部署与平滑重载:申请成功后,它能自动将证书复制到 Nginx 或 Apache 等 Web 服务器的指定目录,并自动执行重载命令(如 nginx -s reload),实现零停机更新。
  • 自动续期(核心优势):安装后会自动创建 Cron 定时任务,默认每 60 天检查一次证书状态。在证书到期前,它会自动完成续签、部署和重载的全套流程,彻底解放运维人员的双手。
  • 支持泛域名证书:只需一条简单的命令,就能为 *.example.com 及其所有子域名签发一张通配符证书,极大地简化了多子域名站点的管理。
  • 轻量且零依赖:由于是纯 Shell 编写,它不需要 Python 等复杂的运行环境,不污染系统文件,几乎可以在所有主流的 Unix-like 系统(Linux、macOS 等)上直接运行。

产品对比

特性 certd certbot acme.sh
定位 国产证书自动化管理平台 Let's Encrypt 官方客户端 社区流行的轻量 Shell 脚本
协议支持 ACME v2 ACME v2 ACME v2
证书来源 Let's Encrypt、ZeroSSL、Google Trust 等 Let's Encrypt(官方) Let's Encrypt、ZeroSSL、Google Trust、Buypass 等
部署方式 独立服务 + Web UI 命令行工具 纯 Shell 脚本
自动续期 ✅ 内置定时任务 ✅ 需配置 cron/systemd ✅ 内置 cron 自动安装
多服务器部署 ✅ 原生支持 ❌ 需手动复制或配合其他工具 ❌ 需手动复制或 rsync
Web 管理界面 ✅ 有 ❌ 无 ❌ 无
证书监控/告警 ✅ 到期提醒、失败告警 ❌ 无 ❌ 无
Nginx/Apache 自动配置 ⚠️ 需手动配置或配合 ✅ 自动修改配置 ❌ 手动配置
安装复杂度 中等(需部署服务) 低(包管理器安装) 低(curl 一键安装)
依赖 Java/Node + 数据库 Python + 依赖包 纯 Shell,几乎零依赖
适合场景 企业级、多服务器、集中管理 个人/单服务器、快速上手 轻量环境、Docker、嵌入式

一、 执行步骤

第一步:安全备份(回退保障)

在修改任何配置前,先备份现有的证书文件和 Nginx 配置文件(以编译安装的为例,通过系统包管理工具安装的目录可能不一致!)。如果后续任何环节出错,直接还原即可。

# 备份当前可用的 SSL 证书文件(如果不可用了可以忽略)
cp /usr/local/nginx/conf/ssl/XXX.pem /usr/local/nginx/conf/ssl/XXX.pem.bak
cp /usr/local/nginx/conf/ssl/XXX.key /usr/local/nginx/conf/ssl/XXX.key.bak

# 备份 Nginx 配置文件(主配置)
cp /usr/local/nginx/conf/nginx.conf /usr/local/nginx/conf/nginx.conf.bak
# 如果是单独配置
cp /usr/local/nginx/conf/vhost/XXXX.conf /usr/local/nginx/conf/vhost/XXXX.conf.bak

第二步:安装与配置 acme.sh

# 安装 acme.sh(替换为你的真实邮箱)
curl https://get.acme.sh | sh -s email=your_email@example.com
source ~/.bashrc

# 切换默认 CA 为 Let's Encrypt
acme.sh --set-default-ca --server letsencrypt

# 开启 acme.sh 自动升级
acme.sh --upgrade --auto-upgrade

如果是国内的服务器或者主机,请使用gitee

git clone https://gitee.com/neilpang/acme.sh.git
cd acme.sh
./acme.sh --install -m 你的邮箱

第三步:配置 DNS API 并申请证书

# 配置阿里云 DNS API 环境变量
export Ali_Key="你的AccessKey_ID"
export Ali_Secret="你的AccessKey_Secret"

# 签发证书(包含主域名和泛域名)
acme.sh --issue --dns dns_ali -d XXX.com -d '*.XXX.com'

第四步:安装证书与平滑重载

将证书复制到 Nginx 目录并绑定重载命令:

acme.sh --install-cert -d XXX.com \
--key-file       /usr/local/nginx/conf/ssl/XXX.com.key \
--fullchain-file /usr/local/nginx/conf/ssl/XXX.com.pem \
--reloadcmd      "/usr/local/nginx/sbin/nginx -s reload"

检查 Nginx 配置语法并平滑重载:

/usr/local/nginx/sbin/nginx -t
/usr/local/nginx/sbin/nginx -s reload

第五步:配置定时任务(自动续期)

acme.sh 在安装时会自动创建 Cron 定时任务,但生产环境必须手动验证其是否生效,防止因系统更新或权限问题导致续期失败。

  1. 检查现有 Cron 任务
crontab -l | grep acme.sh

正常输出应包含类似以下内容:

0 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
  1. 若任务缺失,手动添加
acme.sh --cron --install-cronjob
  1. 验证续期逻辑(Dry Run)

无需等待证书到期,可强制触发一次续期检查,确认 DNS API 调用及 Nginx Reload 是否正常:

acme.sh --cron --force

注意--force 会强制触发续期流程,即使证书未到期。生产环境建议仅在首次配置后验证一次,避免频繁触发 Let's Encrypt 的 Rate Limit。


二、 🚨避坑指南

DNS API 的 AccessKey ?

为了生产环境安全,必须在 RAM 访问控制中创建专属子用户(如 acme-bot),仅授予 AliyunDNSFullAccess 权限。这样即使服务器被攻破,黑客也只能操作 DNS,无法动你的 ECS 或数据库。

为什么不能直接用 acme.sh 的默认目录?

acme.sh 默认的证书目录(~/.acme.sh/)是工具内部工作目录。必须通过 --install-cert 命令将证书复制到 Nginx 的固定目录中,并配合 --reloadcmd 参数,这样未来的自动续期才能正确触发 Nginx 重载。

常见错误 1:ERR_SSL_VERSION_OR_CIPHER_MISMATCH

现象:Nginx reload 成功,但浏览器访问提示“您的连接不是私密连接”或 ERR_SSL_VERSION_OR_CIPHER_MISMATCH

原因分析:旧版 Nginx 配置中包含了 RC4-SHA 等已被现代浏览器彻底废弃的弱加密算法。

解决方案:替换 ssl_ciphers 为现代浏览器支持的强加密套件。

# 错误配置示例
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:...:RC4-SHA:...;

# 正确配置示例
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;

常见错误 2:ECC 证书验证命令误用

现象:使用 openssl ec -noout -modulus 验证私钥时报错 unknown option -modulus,或者输出的 MD5 值为空字符串的哈希值(d41d8cd98f00b204e9800998ecf8427e)。

原因分析-modulus 仅适用于 RSA 密钥。acme.sh 默认生成的 ECC 私钥为 PKCS#8 格式,不支持该参数。

解决方案:使用通用的 pkey 命令提取公钥进行比对。

# 验证证书公钥
openssl x509 -noout -pubkey -in /path/to/fullchain.cer | openssl md5
# 验证私钥公钥(注意使用 pkey)
openssl pkey -noout -pubout -in /path/to/private.key | openssl md5

注:两个命令输出的 MD5 值必须完全一致,否则证书与私钥不匹配。

常见错误 3:ERR_CERT_COMMON_NAME_INVALID

现象:访问 XXX.com 时,浏览器提示证书通用名称无效。点击证书发现仅包含 XXX.com

原因分析:申请证书时仅指定了 -d XXX.com,未包含 www 子域名。现代浏览器要求 SAN(使用者可选名称)必须精确匹配访问的域名。

解决方案:强制重新签发包含所有域名的证书。

acme.sh --force --issue --dns dns_ali -d XXX.com -d XXX.com

注:如果希望一劳永逸,建议直接申请泛域名证书 -d '*.XXX.com'

常见错误 4:签发时报错 curl error code: 60

现象:执行 acme.sh --issue 时,提示 Cannot init API for: https://acme-v02.api.letsencrypt.org/directory,且伴随 CURLE_PEER_FAILED_VERIFICATION (60) 错误。

原因分析:服务器的 CA 证书包过期或缺失,导致本地 curl 无法验证 Let's Encrypt 官方服务器的 SSL 证书信任链。

解决方案:更新系统 CA 证书包。

# CentOS / Alibaba Cloud Linux
yum update -y ca-certificates

# Ubuntu / Debian
apt-get update && apt-get install --reinstall ca-certificates

更新后,使用 curl -v https://acme-v02.api.letsencrypt.org/directory 验证能正常返回 JSON 数据即可重新签发。


三、 任务总结

  • 安全性提升:全程通过备份机制保障生产环境可回退;使用 RAM 子用户保护云账号安全。
  • 运维效率提升:彻底告别手动续签,acme.sh 的 crontab 任务会在证书到期前 30 天自动续期并平滑重载 Nginx,实现真正的“一次配置,永久免维护”。
  • 可观测性增强:通过第五步的 Dry Run 验证,确保自动续期链路在首次配置时即通过验证,避免“证书到期才发现 Cron 失效”的生产事故。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇