ACME 客户端与自动化
lego 通过 DNS-01 申请 Let's Encrypt 证书
lego 用一条 lego run 命令调用 DNS 服务商 API 完成 DNS-01 验证,为 example.com 和 *.example.com 签发 Let's Encrypt 通配符证书。部署钩子负责安装证书和重载 Web 服务,systemd 定时器每天运行一次负责续期。
适用于 Linux 上的 lego v5(2026 年 5 月发布,最新版本以 GitHub releases 为准)。示例用阿里云 DNS,也给出腾讯云 DNSPod 的写法。
前提条件
DNS-01 只要求能调用 DNS API,不需要开放入站端口,80 端口被封或未备案也能用。
- 带 systemd 的 Linux 服务器,有 sudo 权限。
- 域名解析托管在 lego 支持的服务商(
lego dnshelp可以列出全部)。 - 阿里云:创建 RAM 子账号,只授予云解析 DNS 的管理权限(如
AliyunDNSFullAccess),生成 AccessKey。腾讯云:在访问管理里创建子用户并授予 DNSPod 权限,生成 SecretId/SecretKey。 - 服务器能访问 Let's Encrypt 和 DNS 服务商的 API。
第一步:安装 lego
从 lego 的 GitHub releases 页面下载对应平台的压缩包,然后安装:
tar -xzf lego_*_linux_amd64.tar.gz lego
sudo install -m 755 lego /usr/local/bin/lego
lego --version
文档列出的其他方式:go install github.com/go-acme/lego/v5@latest(需要 Go 1.25+)、Docker 镜像 goacme/lego、Homebrew 和发行版软件包。从 v4 升级的,先对原数据目录运行 lego migrate。
第二步:保存 DNS 密钥
把密钥写进只有 root 能读的环境变量文件,避免留在命令历史里。阿里云 DNS:
sudo install -d -m 700 /etc/lego
sudo tee /etc/lego/env > /dev/null <<'EOF'
ALICLOUD_ACCESS_KEY=your-access-key-id
ALICLOUD_SECRET_KEY=your-access-key-secret
EOF
sudo chmod 600 /etc/lego/env
腾讯云 DNSPod 改用 TENCENTCLOUD_SECRET_ID 和 TENCENTCLOUD_SECRET_KEY,后面的 --dns alidns 换成 --dns tencentcloud。
第三步:签发证书
一条 lego run 完成签发,--dns alidns 表示通过阿里云 DNS API 做 DNS-01 验证:
sudo bash -c 'set -a; . /etc/lego/env; set +a; \
lego run --accept-tos --path /etc/lego \
--dns alidns -d example.com -d "*.example.com"'
lego 会自动添加 _acme-challenge TXT 记录、等待生效、完成验证并清理记录。想用 Let's Encrypt 的 45 天证书,加 --profile tlsserver(见 Let's Encrypt 证书配置文件);调试时加 --server https://acme-staging-v02.api.letsencrypt.org/directory 使用测试环境。
第四步:添加部署钩子
--deploy-hook 在证书创建或续期后运行,lego 通过 LEGO_HOOK_CERT_PATH 和 LEGO_HOOK_CERT_KEY_PATH 传入文件位置:
sudo tee /etc/lego/deploy.sh > /dev/null <<'EOF'
#!/bin/sh
set -e
install -d -m 700 /etc/nginx/ssl
install -m 644 "$LEGO_HOOK_CERT_PATH" /etc/nginx/ssl/example.com.crt
install -m 600 "$LEGO_HOOK_CERT_KEY_PATH" /etc/nginx/ssl/example.com.key
systemctl reload nginx
EOF
sudo chmod 755 /etc/lego/deploy.sh
Nginx 引用 /etc/nginx/ssl/example.com.crt(lego 默认把签发者证书打包进 .crt,就是完整证书链)和 /etc/nginx/ssl/example.com.key。首次部署用 lego certificates list --path /etc/lego 找到文件,手动复制一次。
验证
配置正确时,example.com 和 www.example.com 返回同一张 Let's Encrypt 证书,SAN 里有 example.com 和 *.example.com。用 SSL 证书检查 检查,或在终端运行:
curl ssl.sh/example.com
curl ssl.sh/www.example.com
在服务器上:
sudo lego certificates list --path /etc/lego
openssl x509 -in /etc/nginx/ssl/example.com.crt -noout -ext subjectAltName -enddate
自动续期
lego 没有常驻进程,每天运行一次 lego run,没到期就什么都不做。--renew-days 0(默认)时按证书有效期自动计算续期时间,并按 Let's Encrypt 的 ARI 窗口续期(除非加了 --ari-disable)。创建服务和定时器:
# /etc/systemd/system/lego.service
[Unit]
Description=lego certificate renewal
[Service]
Type=oneshot
EnvironmentFile=/etc/lego/env
ExecStart=/usr/local/bin/lego run --accept-tos --path /etc/lego --dns alidns -d example.com -d *.example.com --deploy-hook /etc/lego/deploy.sh
# /etc/systemd/system/lego.timer
[Unit]
Description=Daily lego renewal check
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload && sudo systemctl enable --now lego.timer
sudo systemctl start lego.service && sudo journalctl -u lego -n 20 --no-pager
续期前 lego 默认会随机等待一段时间,手动运行时可加 --no-random-sleep。每天检查足以应对 2027 年 2 月 10 日的 64 天证书和 2028 年 2 月 16 日的 45 天证书。建议把域名加到 ssl.sh 监控(开发中)。
常见问题排查
- unknown command "renew" 或 flag provided but not defined:在 lego v5 上用了 v4 的写法,见上面的常见问题和迁移文档。
- alidns: ... Forbidden 或 InvalidAccessKeyId:AccessKey 错误或 RAM 子账号没有云解析权限。
- propagation: time limit exceeded:加大传播等待时间(
--dns.propagation.wait,见lego run --help),或确认域名的权威 DNS 确实在你配置的服务商。 - CAA record prevents issuance:见 CAA 记录阻止签发。
- 触发频率限制:生产环境测试次数太多,改用测试环境,见 Let's Encrypt 频率限制。
- Web 服务还在用旧证书:部署钩子没运行或失败,查看
journalctl -u lego。
常见问题
按旧教程运行 lego renew 报错?
lego v5 删除了 renew 命令,证书到期时 lego run 会自动续期。参数也要写在子命令后面(lego run --dns alidns,而不是 lego --dns alidns run),部分参数改了名。已有 v4 数据目录的先运行一次 lego migrate,再改脚本。
lego 和 acme.sh 选哪个?
跑在 systemd 或容器里选 lego,想要现成的 cron 和部署钩子选 acme.sh。lego 是单个二进制、参数清晰;acme.sh 是 Shell 脚本,安装后自带 cron 和大量部署钩子,国内教程多。两者都支持阿里云 DNS 和 DNSPod,只要配置好每日检查,都能应对越来越短的证书有效期。acme.sh 的写法见 acme.sh + 阿里云 DNS/DNSPod。
证书文件保存在哪里?
在 --path 目录(默认是当前目录下的 .lego)的 certificates/ 子目录里,第一个域名是通配符时文件名形如 _.example.com.crt。用 lego certificates list --path /etc/lego 查看确切路径,不要靠猜。