3. ACME客户端选型与部署
ACME协议本身只是一套规范,真正与Let's Encrypt、ZeroSSL、Buypass等CA交互、完成账户注册、订单创建、挑战应答、证书签发与续期的,是运行在服务器上的ACME客户端。选错客户端,往往意味着后续运维要长期忍受依赖冲突、续期失败、配置难以自动化等问题。因此,客户端选型不是"随便装一个能签证书就行",而是要根据运行环境、自动化程度、是否已有Web服务器、是否需要DNS验证、团队技术栈等因素综合判断。
四类主流客户端的定位差异
目前生产环境中最常见的四类客户端,可以按"设计哲学"分成两组:一组是通用型命令行客户端,包括acme.sh、certbot、lego,它们只负责把证书签下来,如何部署、如何重载服务由使用者自己决定;另一组是集成型Web服务器,以Caddy为代表,它把ACME客户端内嵌进服务器本身,证书申请、续期、加载全自动完成,用户几乎不需要感知ACME的存在。
acme.sh是一个纯Shell脚本实现的客户端,最大特点是零依赖——只要有sh、curl或wget、openssl就能跑,不依赖Python、Go等运行时。它默认使用ZeroSSL作为CA,也支持切换到Let's Encrypt。acme.sh支持HTTP-01、DNS-01、TLS-ALPN-01三种挑战,尤其DNS-01配合各大DNS服务商的API可以实现通配符证书的全自动签发,这是它被大量用于内网、无公网80端口场景的核心原因。安装方式极简:
curl https://get.acme.sh | sh -s email=ops@example.com
# 或
git clone https://github.com/acmesh-official/acme.sh.git
cd acme.sh && ./acme.sh --install -m ops@example.com
安装后会在用户目录下生成~/.acme.sh,并自动注册一个cron任务用于续期。它的续期不是靠systemd timer,而是靠cron调用自身,因此对系统服务管理方式不敏感,在容器、精简系统、老式发行版上都能工作。
certbot由EFF主导开发,是Let's Encrypt官方早期推荐的客户端,Python实现,生态最成熟。它的优势在于与Nginx、Apache的深度集成:certbot --nginx可以自动读取现有server块、插入证书路径、配置跳转,甚至自动reload。对于已经用Nginx/Apache托管大量站点的团队,certbot的插件模式能显著降低手工改配置的成本。安装通常通过系统包管理器:
# Debian/Ubuntu
apt install certbot python3-certbot-nginx
# RHEL/CentOS
dnf install certbot python3-certbot-nginx
但certbot的Python依赖较重,在最小化容器镜像中安装体积较大,且不同发行版打包的版本差异明显,插件行为可能不一致。它更适合"传统虚拟机+系统包管理"的运维模式。
lego是Go语言编写的单二进制客户端,编译后无运行时依赖,跨平台分发方便。它同时支持ACME v2和多种DNS服务商,命令行参数清晰,也常被当作库嵌入其他Go程序。安装只需下载对应平台的二进制:
# 以Linux amd64为例
curl -L https://github.com/go-acme/lego/releases/latest/download/lego_v4_linux_amd64.tar.gz | tar xz
mv lego /usr/local/bin/
lego适合Kubernetes环境、CI流水线、以及需要把证书签发逻辑写进自有程序的场景。它本身不管理续期调度,需要配合cron或K8s CronJob。
Caddy则完全不同。它是一个用Go写的Web服务器,内置ACME客户端,只要域名解析正确、80/443可达,启动时就会自动申请证书并启用HTTPS。配置文件中只需写域名,不需要写证书路径:
example.com {
root * /var/www/html
file_server
}
Caddy会自动完成HTTP-01或TLS-ALPN-01挑战、证书存储、到期前续期和热加载。它适合新项目、反向代理、内部工具站点,但不适合"已有Nginx且不想更换"的存量环境。
选型判断:从运行环境反推客户端
与其背客户端的特性表,不如从实际约束出发做判断。下面这张图把常见约束与推荐客户端对应起来,可作为选型时的快速参照。
安装方式与运行环境对照
把四类客户端的安装与运行特征放在一起对比,能更直观地看出各自适合的土壤。
| 客户端 | 实现语言 | 典型安装方式 | 运行依赖 | 续期调度 | 适用场景 |
|---|---|---|---|---|---|
| acme.sh | Shell | curl脚本 / git clone | sh、curl/wget、openssl | 内置cron | 精简系统、容器、DNS-01、通配符 |
| certbot | Python | apt/dnf/pip | Python3及插件包 | systemd timer / cron | 已有Nginx/Apache的虚拟机 |
| lego | Go | 二进制下载 / 包管理 | 无(静态二进制) | 外部cron / K8s CronJob | K8s、CI、嵌入式调用 |
| Caddy | Go | 二进制 / 包管理 / 容器 | 无(静态二进制) | 内置自动续期 | 新站点、反向代理、全自动HTTPS |
部署时的关键注意点
无论选哪个客户端,有几条工程经验值得提前确认。第一,续期调度必须可观测。acme.sh的cron、certbot的systemd timer、lego的外部cron,都可能因为环境变量缺失、路径变化而静默失败。建议在续期命令后接一个通知钩子,或定期检查证书剩余有效期。第二,证书私钥权限要收紧。acme.sh默认把私钥放在~/.acme.sh下,certbot放在/etc/letsencrypt下,部署到Web服务器目录时应确保只有服务账户可读。第三,CA选择要明确。acme.sh默认ZeroSSL,certbot默认Let's Encrypt,lego和Caddy也各有默认值,生产环境应显式指定CA,避免因默认值变化导致行为漂移。第四,测试环境先用staging。Let's Encrypt和ZeroSSL都提供staging端点,调试阶段用staging可以避免触发生产环境的速率限制。
选型的本质是匹配约束,而不是追求"最强"。一个只有80/443可达、跑着Nginx的虚拟机,用certbot最省事;一个K8s集群里需要为Ingress自动签发通配符证书,lego或acme.sh配合DNS API更合适;一个全新项目从零开始,直接上Caddy可以把证书这件事彻底交给服务器。理解每个客户端的设计取舍,才能在具体环境中做出不后悔的选择。