本文目录导读:

- 方案一:Certbot + cron(最通用,适用于 Nginx/Apache)
- 方案二:使用 acme.sh(更灵活,野卡证书 & 多种 DNS API)
- 方案三:使用 systemd timer(替代 cron,更精细的控制)
- 常见问题与检查
- 总结建议
要实现证书的自动化续期,最主流的方案是使用 Let's Encrypt 的 Certbot 工具,配合 cron 或 systemd timer 定时任务。
以下是几种常见场景的自动化续期脚本和配置方法:
Certbot + cron(最通用,适用于 Nginx/Apache)
这是最标准、最稳定的方式,Certbot 在安装时通常会自动添加一个 systemd timer,但如果想自己写脚本控制,可以按以下步骤操作。
核心命令
Certbot 续期命令非常简单,它会自动检测所有已安装但即将过期的证书并尝试续期:
certbot renew
这个命令非交互式运行,不会停止服务,如果续期成功,通常需要重载 Web 服务器以加载新证书。
续期后重载服务的钩子
创建一个脚本 /etc/letsencrypt/renewal-hooks/post/reload-services.sh如下:
#!/bin/bash # 续期成功后执行(如果是 Nginx) systemctl reload nginx # 如果是 Apache # systemctl reload apache2 # 如果是 Docker 内的 Nginx(示例,需要根据实际容器名调整) # docker exec nginx-container nginx -s reload
给脚本加上执行权限:
chmod +x /etc/letsencrypt/renewal-hooks/post/reload-services.sh
Certbot 会自动执行 renewal-hooks/post/ 目录下的脚本。
设置定时任务 (cron)
使用 crontab -e 添加以下行:
# 每天凌晨 3 点检查一次,如果证书将在 30 天内过期则自动续期 0 3 * * * /usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"
参数说明:
--quiet:非错误信息不输出到日志。--deploy-hook:在续期成功后才执行后面的命令(比写在 post-hook 里更直接)。- 频率建议:每天一次,Let's Encrypt 证书有效期 90 天,Certbot 会在证书剩余时间 < 30 天时自动续期,每天检查不会对服务器造成负担。
使用 acme.sh(更灵活,野卡证书 & 多种 DNS API)
如果你的证书是 通配符域名(*.example.com),或者使用 DNS 验证(Cloudflare、阿里云 DNS),推荐使用 acme.sh。
安装与配置(以 Cloudflare 为例)
# 安装 curl https://get.acme.sh | sh # 设置 Cloudflare API(需要先设置环境变量) export CF_Token="你的Cloudflare API Token" export CF_Zone_ID="Zone ID" # 第一次申请证书(自动续期) acme.sh --issue --dns dns_cf -d example.com -d '*.example.com'
续期脚本
acme.sh 会自动安装一个 cron 任务,无需额外配置,你可以使用以下命令查看:
crontab -l # 你会看到类似这样的行: # 0 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
续期后部署证书到 Nginx
在nginx配置中,引用 acme.sh 生成的证书路径(通常是 /root/.acme.sh/域名/fullchain.cer)。
然后在 cron 中或者使用 --reloadcmd 参数自动执行重载:
acme.sh --issue ... --reloadcmd "systemctl reload nginx"
这样每次自动续期后,Nginx 会自动重载。
使用 systemd timer(替代 cron,更精细的控制)
如果你更喜欢 systemd 而不是 cron,可以创建一个简单的 timer。
- 创建服务文件
/etc/systemd/system/certbot-renew.service:[Unit] Description=Certbot Renewal
[Service] Type=oneshot ExecStart=/usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"
2. **创建定时器文件** `/etc/systemd/system/certbot-renew.timer`:
[Unit] Description=Daily Certbot Renewal
[Timer] OnCalendar=daily RandomizedDelaySec=1h Persistent=true
[Install] WantedBy=timers.target
3. **启用并启动定时器**:
```bash
systemctl daemon-reload
systemctl enable certbot-renew.timer
systemctl start certbot-renew.timer
常见问题与检查
如何测试脚本是否工作?
# 模拟续期(不会真正修改证书) certbot renew --dry-run # dry-run 成功,说明配置没问题
证书路径在哪里?
- Certbot:
/etc/letsencrypt/live/yourdomain.com/ - acme.sh:
/root/.acme.sh/yourdomain.com/
确保 Nginx/Apache 配置文件中 ssl_certificate 和 ssl_certificate_key 指向正确的路径。
手动触发一次续期(即使未到期)
# 强制续期(会受 Let's Encrypt 频率限制,建议仅在测试时用) certbot renew --force-renewal
日志查看
# Certbot 日志 tail -f /var/log/letsencrypt/letsencrypt.log # acme.sh 日志 tail -f /root/.acme.sh/acme.sh.log
总结建议
- 如果你用的是标准的 HTTP 验证(如 Nginx/Apache):用 Certbot + cron 最省事。
- 如果需要通配符证书或 DNS 验证:用 acme.sh,它支持更多 DNS 提供商,且自动续期机制更成熟。
- 部署时:一定要把定时任务设置到 每天执行(而不是每周),因为即使失败也有机会重试,而 Let's Encrypt 不会在你重复运行命令时给你重复发证书,它只在需要时才续期。
一个完整的自动化脚本示例(适用于初学):
#!/bin/bash
# 1. 尝试续期
/usr/bin/certbot renew --quiet
# 2. 检查是否需要重载服务(如果续期成功,deploy-hook 会处理)
# 这里仅做兜底:如果证书文件有更新,就重载
if [ -f /var/run/nginx.pid ]; then
nginx -t && systemctl reload nginx
fi
把这个脚本放入 cron,每天执行一次即可。