在配置个人博客或网站的 HTTPS 时,Let's Encrypt 配合 Certbot 是最主流的免费方案。理论上它能实现“一次配置,永久自动续期”。但在实际操作中(特别是涉及到服务器迁移、反向代理或从旧配置迁移时),我们经常会遇到 404 Unauthorized 或 Plugin not installed 等报错。
本文记录了一次真实的排查过程,涵盖了安装插件、解决反向代理验证失败、多域名证书合并以及清理“僵尸”证书的全流程。
1. 为什么自动续期会失败?
Certbot 有两种常用的验证模式:
- Webroot 模式 (
--webroot):Certbot 在网站根目录创建一个验证文件,Let's Encrypt 访问这个文件来验证。 - Nginx 插件模式 (
--nginx):Certbot 自动修改 Nginx 配置来完成验证,验证完恢复原状。
常见坑点:如果你的 Nginx 配置了反向代理(例如代理到 Tomcat、Node.js ),Webroot 模式创建的文件会被 Nginx 转发给后端,导致 Let's Encrypt 访问不到文件(报 404 错误)。
解决方案:强烈建议使用 Nginx 插件模式,它能智能处理路由,无需关心反向代理。
2. 基础环境准备
首先,确保你的服务器上不仅安装了 Certbot,还安装了对应的 Nginx 插件。很多续期失败的原因仅仅是缺少这个插件。
Ubuntu / Debian:
sudo apt update
sudo apt install certbot python3-certbot-nginx
CentOS / Alibaba Cloud Linux:
sudo yum install python3-certbot-nginx
# 或者
sudo yum install certbot-nginx
3. 实战:修复 "Unauthorized" 并合并多域名
假设你有两个域名 blog.example.com 和 img.example.com。之前可能分别申请了证书,且使用的是容易出错的 Webroot 模式。
运行一次“模拟续期”命令。这个命令会跑一遍流程,但不会真的替换证书。
certbot renew --dry-run
当我们尝试续期时,可能会遇到如下报错:
Certbot failed to authenticate some domains ... Invalid response from ... 404
步骤一:强制使用 Nginx 插件重新配置
不需要手动修改 Nginx 配置文件,直接运行以下命令,同时加上你所有的域名:
# -d 后面跟上你所有的域名
sudo certbot --nginx -d blog.example.com -d img.example.com
系统会提示:
You have an existing certificate... Do you want to expand and replace this existing certificate with the new certificate?
输入 E (Expand) 进行扩展合并。
这样做有两个好处:
- 强制切换到了更稳定的 Nginx 插件模式。
- 将多个域名合并到一张证书里,管理更方便。
4. 清理“僵尸”证书配置
合并证书后,最容易被忽略的一步来了。
当你运行 certbot renew --dry-run 测试时,可能会发现:一个成功了,但还有一个失败了。
The following simulated renewals succeeded:
/etc/letsencrypt/live/blog.example.com/fullchain.pem (success)
The following simulated renewals failed:
/etc/letsencrypt/live/img.example.com/fullchain.pem (failure)
原因:因为我们把 img 域名合并到了 blog 的证书里,但系统里还残留着旧的、独立的 img 证书配置文件。这个旧配置还在尝试用老方法续期,自然会报错。
解决方法:
删除旧证书:
# 注意:请根据上一步显示的 Certificate Name 准确填写
sudo certbot delete --cert-name img.example.com
查看当前所有证书:
sudo certbot certificates
你会看到一个是包含所有域名的新证书,一个是多余的旧证书。
5. 最终验证 (关键)
不要以为配置完就没事了,一定要进行“模拟续期”测试,确保自动任务能正常工作。
输入命令:
certbot renew --dry-run
如果看到输出中全是 success,没有 failure,恭喜你!你的 HTTPS 证书已经配置为全自动续期,只要服务器不关机,以后都不用操心过期问题了。
检查定时任务是否存在(可选,用于确认),你可以检查一下系统里是否有这个“闹钟”。
systemctl list-timers | grep certbot
如果你看到类似下面的输出,说明定时任务正在运行:
Fri 2020-11-28 20:30:00 CST 9h left n/a n/a certbot.timer certbot.service
原理说明:Certbot 会自动在系统(Cron 或 Systemd)中添加定时任务,每天检查两次。如果证书有效期少于 30 天,它会自动执行续期并重载 Nginx。
总结
在反向代理场景下配置 HTTPS,Nginx 插件模式是最佳选择。
- 装插件:确保
python3-certbot-nginx已安装。 - 用插件:使用
certbot --nginx -d 域名申请或覆盖证书。 - 删僵尸:合并证书后,记得
certbot delete删除旧的冗余配置。 - 测续期:
certbot renew --dry-run是检验真理的唯一标准。