1. 背景与适用范围
本文介绍使用 Let's Encrypt、Nginx 与 Certbot 自动续约 HTTPS 证书的通用方案,适用于 Ubuntu 等使用 systemd 的 Linux 发行版,不依赖 Docker。
文中的 example.com、www.example.com 和 new.example.com 均为示例域名,请替换为实际域名。
2. 架构
flowchart LR
U["浏览器"] -->|"HTTPS 443"| N["Nginx"]
N -->|"读取证书与私钥"| C["/etc/letsencrypt/live/example.com/"]
T["systemd certbot.timer"] -->|"定期执行 certbot renew"| B["Certbot"]
B -->|"ACME HTTP-01 校验"| L["Let's Encrypt"]
B -->|"更新证书文件"| C
B -->|"续约成功后执行"| H["deploy hook"]
H -->|"验证配置并重载"| N
职责说明:
- Nginx:处理 HTTP/HTTPS 请求,并通过证书和私钥提供 TLS。
- Certbot:向 Let's Encrypt 申请、续约和部署证书。
- Let's Encrypt:签发证书的 ACME 证书颁发机构。
- systemd timer:定期运行
certbot renew,仅在证书进入续约窗口时真正续约。
3. 示例配置
Nginx 的 HTTPS server block 应引用 Certbot 管理的证书文件:
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
这些文件由 Certbot 管理。证书续约后,Nginx 重载才会在新建 TLS 连接中使用新证书。
Certbot 的续约配置通常位于:
/etc/letsencrypt/renewal/example.com.conf
使用 Nginx 插件时,续约配置中通常包含:
authenticator = nginx
installer = nginx
server = https://acme-v02.api.letsencrypt.org/directory
4. 自动续约流程
certbot.timer 会定期执行 certbot renew。默认情况下,Certbot 会在证书距离到期日不足 30 天时尝试续约。
续约成功后,通常会经历以下步骤:
- Certbot 向 Let's Encrypt 发起续约请求。
- Certbot 使用 Nginx 插件处理
/.well-known/acme-challenge/的 HTTP-01 校验。 - Let's Encrypt 通过公网 80 端口验证域名。
- 新证书写入
/etc/letsencrypt/archive/example.com/。 /etc/letsencrypt/live/example.com/中的链接指向最新证书。- Certbot 通过已配置的 installer 或 deploy hook 部署新证书,并重载 Nginx。
注意:HTTP-01 校验要求 Let's Encrypt 能通过公网访问 80 端口。即使网站会将 HTTP 重定向至 HTTPS,验证期间也必须允许挑战请求通过。
4.1 确保续约后重载 Nginx
建议创建显式的 deploy hook,以确保只有在续约成功且 Nginx 配置检查通过后才重载服务:
# 创建续约成功后执行的 Nginx 重载钩子
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh >/dev/null <<'EOF'
#!/bin/sh
# 仅在 Nginx 配置检查通过时重载服务
nginx -t && systemctl reload nginx
EOF
# 允许 Certbot 执行部署钩子
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
使用测试环境验证续约和部署钩子:
# 演练续约流程,并执行 deploy hook
certbot renew --dry-run --run-deploy-hooks
5. 日常检查
5.1 查看证书状态
# 列出 Certbot 管理的证书及到期时间
certbot certificates
5.2 查看定时器状态和下次执行时间
# 查看定时器是否已启用
systemctl status certbot.timer
# 查看 Certbot 相关定时任务的下次执行时间
systemctl list-timers --all | grep certbot
5.3 查看最近续约日志
# 查看最近的续约、成功和错误日志
grep -Ei 'renew|success|error|example\.com' /var/log/letsencrypt/letsencrypt.log | tail -n 100
5.4 验证 Nginx 使用的证书
# 查询远端站点返回的证书签发者、主题和有效期
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -issuer -subject -dates
5.5 检查 Nginx 配置
# 检查配置语法并查看服务状态
nginx -t
systemctl status nginx
6. 安全的续约演练
使用 Let's Encrypt 测试环境验证续约流程,不会消耗正式签发额度:
# 使用测试环境模拟续约
certbot renew --dry-run
演练成功后无需重启服务器。若配置了 deploy hook,可使用前文的 --run-deploy-hooks 参数同时验证重载流程。
7. 手动续约
通常无需手动续约。仅在排障或证书接近到期且定时任务异常时使用:
# 对进入续约窗口的证书执行续约
certbot renew
仅对单个证书强制重新申请会受到 Let's Encrypt 频率限制,应避免在日常操作中使用:
# 强制续约指定证书,按实际证书名称替换 example.com
certbot renew --cert-name example.com --force-renewal
执行前后均应检查:
# 确认证书状态与 Nginx 配置均正常
nginx -t
certbot certificates
8. 为新服务器首次签发证书
前提条件:
- 域名 A 或 AAAA 记录已解析到服务器公网 IP。
- 云防火墙和本机防火墙允许公网访问 TCP 80、443。
- Nginx 已安装,并存在包含目标
server_name的 HTTP server block。 - 80 端口未被其他服务占用。
安装组件:
# 更新软件包索引并安装 Nginx、Certbot 及其 Nginx 插件
sudo apt-get update
sudo apt-get install -y nginx certbot python3-certbot-nginx
先验证 Nginx:
# 检查配置并设置 Nginx 开机启动
sudo nginx -t
sudo systemctl enable --now nginx
签发并自动写入 Nginx TLS 配置:
# 为示例主域名和 www 子域名签发证书
sudo certbot --nginx -d example.com -d www.example.com
完成后验证:
# 检查证书、Nginx 配置、定时器和续约演练
sudo certbot certificates
sudo nginx -t
sudo systemctl status certbot.timer
sudo certbot renew --dry-run
9. 域名增加或变更
新增域名前,先完成 DNS、80/443 防火墙和 Nginx server_name 配置,再执行:
# 重载更新后的 Nginx 配置
sudo nginx -t && sudo systemctl reload nginx
# 为更新后的域名集合重新申请或扩展证书
sudo certbot --nginx --cert-name example.com -d example.com -d www.example.com -d new.example.com
域名不再使用时,不要直接删除 /etc/letsencrypt/live/ 下的文件;应先从 Nginx 配置移除对应引用并验证 Nginx,再通过 Certbot 管理证书生命周期。
10. 常见故障排查
10.1 HTTP-01 校验失败
检查 DNS 是否已指向本机:
# 查询示例域名的解析结果
getent ahosts example.com
检查 80 端口监听:
# 查看 TCP 80 端口的监听进程
ss -ltnp '( sport = :80 )'
检查 Nginx 和云防火墙是否允许 /.well-known/acme-challenge/ 请求。不要只开放 443;HTTP-01 校验需要公网访问 80。
10.2 Nginx 配置检查失败
# 查看 Nginx 配置错误和最近的服务日志
nginx -t
journalctl -u nginx -n 100 --no-pager
先修复 Nginx 配置,再重新运行 certbot renew --dry-run。
10.3 定时器未运行
# 启用 Certbot 定时器并查看服务日志
sudo systemctl enable --now certbot.timer
sudo systemctl status certbot.timer
sudo journalctl -u certbot.service -n 100 --no-pager
部分发行版也会安装 /etc/cron.d/certbot 作为无 systemd 环境下的备用调度方式。应以实际启用的调度方式为准,避免重复执行。
11. 重要文件与权限
| 路径 | 用途 |
|---|---|
/etc/letsencrypt/live/example.com/fullchain.pem |
Nginx 使用的服务器证书与中间证书链 |
/etc/letsencrypt/live/example.com/privkey.pem |
Nginx 使用的私钥,必须严格保护 |
/etc/letsencrypt/archive/example.com/ |
Certbot 保存的历史证书版本 |
/etc/letsencrypt/renewal/example.com.conf |
续约参数 |
/var/log/letsencrypt/letsencrypt.log |
Certbot 日志 |
不要将 privkey.pem 复制到代码仓库、应用目录、聊天记录或不受控的备份介质中。不要手动修改 live 目录内的链接或删除 archive 中的文件。
12. 验证与总结
完成首次签发或续约演练后,应确认 nginx -t 通过、证书有效期符合预期,且 Certbot 的定时任务已启用。日常保持 80 端口可用于 HTTP-01 验证,并定期查看续约日志即可。
Comments