2026-11-02 · HTTPS / 证书 / Nginx / 运维

Let's Encrypt 证书自动续期:从手动 DNS 切到 webroot 的踩坑记录

上一篇写了怎么用 DNS 验证拿免费证书。但那种方式有个硬伤:手动验证的证书不会自动续期,90 天到期前必须手动重跑一次,否则网站证书过期、浏览器报警。

备案通过后域名可以正常访问了,正好把它切换成 webroot(HTTP-01)自动续期。记录一下过程和踩到的坑。

为什么要切

方式 能否自动续期 适用场景
手动 DNS-01❌ 需人工域名未备案、80 端口被拦、无法 HTTP 验证时
webroot HTTP-01✅ certbot timer 自动续域名可正常访问 https 后

切换步骤

1. 确认 webroot 路径可达

证书验证文件会放在网站根目录,先确认 .well-known/acme-challenge/ 能被公网访问:

mkdir -p /var/www/example.com/.well-known/acme-challenge
echo test-ok > /var/www/example.com/.well-known/acme-challenge/testfile
curl -I https://www.example.com/.well-known/acme-challenge/testfile

如果 80 端口配了 301 跳 HTTPS,也没关系:Let's Encrypt 会跟随重定向到 HTTPS 校验。

2. 用 webroot 重新签发,覆盖旧证书

certbot certonly --webroot -w /var/www/example.com \
  -d www.example.com -d example.com \
  --cert-name www.example.com \
  --force-renewal --non-interactive --agree-tos -m you@example.com \
  --deploy-hook "systemctl reload nginx"

关键是 --cert-name 与旧证书一致 + --force-renewal,这样会重写 renewal 配置里的验证方式,而不是新开一套。

3. 确认 renewal 配置已改

grep -E "authenticator|webroot_path" /etc/letsencrypt/renewal/www.example.com.conf
# authenticator = webroot
# webroot_path = /var/www/example.com,

4. 验证自动续期

certbot renew --dry-run
systemctl list-timers certbot.timer

看到模拟续期成功、certbot.timer 有下次执行时间,就说明 90 天到期会自动续,不用再管。

踩坑:certbot 卡住 + 锁文件

测试时遇到:

Another instance of Certbot is already running.

原因是之前一条命令在 SSH 会话被中断后,certbot 进程还活着,一直占着 /var/lib/letsencrypt/.certbot.lock。处理:

ps aux | grep certbot        # 找到残留进程
kill -9 <pid>
rm -f /var/lib/letsencrypt/.certbot.lock

然后重跑 dry-run 即可。别直接删锁不杀进程,否则可能出现两个进程同时写证书目录。

小结

证书自动续期就三步:确认 webroot 可达 → 用 webroot 重新签发一次 → 跑 dry-run 验证。切完之后,HTTPS 这块基本可以几年不用管了。

需要处理服务器 HTTPS/证书/续期问题的,可以找我。