告别手动更新:用acme.sh彻底实现SSL免费证书自动化
现在各大云厂商的免费 SSL 证书有效期基本都缩短到了 3 个月。作为开发者,每隔几个月就去手动申请、下载、上传、重启 Nginx,实在是一件非常繁琐且不科学的事情。
本文将记录一个高阶、优雅的运维方案:使用 acme.sh 配合 DNS API,实现 Let’s Encrypt 泛域名证书(如 *.aliyun.com)的全自动申请,并通过 SSH Deploy 钩子,将证书跨服务器自动推送到另一台运行 Docker Nginx 的节点上,实现真正的零维护、零停机时间(Zero Downtime)热重载。
1. 架构与场景说明
我们拥有两台服务器:
- 服务器 A(证书管理机): 负责安装
acme.sh,与 DNS 服务商通信验证域名,并集中管理所有证书。 - 服务器 B(Web 业务机): 运行具体的 Web 业务,使用 Docker 容器化部署的 Nginx 作为反向代理。
目标: 服务器 A 每天自动检查证书状态,一旦即将过期,自动向 Let’s Encrypt 申请新证书 -> 申请成功后通过 SSH 推送到服务器 B 的指定挂载目录 -> 触发服务器 B 的 Nginx 容器热重载。
2. 安装与环境准备 (服务器 A)
首先在管理机(服务器 A)上安装 acme.sh:
1 | |
注意:切换默认 CA
acme.sh目前默认的证书颁发机构是 ZeroSSL。如果你想使用 Let’s Encrypt,需要执行以下命令完成切换:
1 | |
3. 申请泛域名证书
申请泛域名(通配符)证书推荐使用 DNS API 验证方式。在终端配置你域名服务商(以阿里云为例)的 API 凭证:
3.1 配置环境变量
在服务器 A 上设置环境变量,acme.sh 会自动读取它们来操作 DNS 解析记录:
1 | |
3.2 执行申请命令
执行申请命令,这里同时包含主域名和泛域名:
1 | |
3.3 (可选)将证书安装到本地机器
如果你的目标 Nginx 和申请证书的 acme.sh 运行在同一台服务器上,可以直接执行以下命令安装证书:
1 | |
4. 自动化部署:SSH Deploy 钩子
这是实现“跨服务器自动推送”的关键步骤。
4.1 准备 SSH 密钥,配置免密登录
在服务器 A 上生成 SSH 密钥对,并将公钥添加到服务器 B 的 ~/.ssh/authorized_keys 中,允许无密码登录。
1 | |
4.2 配置 SSH Deploy
1 | |
4.3 执行一键部署与绑定
1 | |
只要执行成功一次,acme.sh 就会将这些路径变量永久记录在配置文件中。以后每次证书自动续签,它都会默默走一遍这个推送和重启的流程。
5. 常见问题答疑 (FAQ)
Q1: 首次执行部署时,提示 cp: cannot stat... No such file or directory?
这是正常的良性报错。acme.sh 为了安全,在覆盖新证书前会尝试备份旧证书。因为是第一次推送,目标服务器上还没有旧文件可供备份,所以会报 cp 找不到文件的错误。脚本会忽略该报错并继续把新证书写入,第二次及以后的推送就不会再有这个提示了。
Q2: 如何测试自动化流程?强制续签会作废原有的证书吗?
1 | |
强制申请下来的新证书和旧证书是相互独立的。 Let’s Encrypt 不会主动吊销旧证书,它依然有效,只是你的 Nginx 已经加载了全新的证书而已。请注意不要频繁测试,以免触发 Let’s Encrypt 每周 5 次的重复签发频率限制。