Ubuntu 22.04 使用 Certbot 为 Nginx 配置 HTTPS 与自动续期
本文记录在 Ubuntu 22.04(Jammy)服务器上,通过 Certbot 为宿主机 Nginx 配置 Let's Encrypt 免费 SSL 证书的完整过程,包括
apt update的 Docker GPG 公钥报错、证书申请、自动续期验证及 Nginx 重载。示例域名为example.cn,实际使用时请替换为自己的域名。
一、环境与部署方案
系统:Ubuntu 22.04 LTS(Jammy)
Web 服务器:宿主机 Nginx
证书工具:Certbot(APT 安装)
示例域名:
example.cn应用服务:可运行在 Docker 容器内,由宿主机 Nginx 统一代理
推荐由宿主机 Nginx 统一监听 80/443 端口并管理 SSL 证书,Docker 业务服务通过其他端口提供 HTTP 接口。避免宿主机 Nginx 与容器 Nginx 同时占用宿主机 80/443 端口。
申请前确认:域名 A/AAAA 记录指向正确服务器;服务器安全组、防火墙放行 80、443;Nginx 配置中存在对应 server_name。
二、安装 Certbot
更新软件包索引:
sudo apt update安装 Certbot 和 Nginx 插件(APT 安装方式):
sudo apt install -y certbot python3-certbot-nginx
certbot --version注意:本文使用 APT 安装和管理 Certbot,不要再用 Snap 重复安装第二份,以免混淆程序路径、配置和定时任务。
2.1 apt update 提示 Docker GPG 公钥缺失
实际遇到的错误:
Err: https://download.docker.com/linux/ubuntu jammy InRelease
The following signatures couldn't be verified because the public key is not available:
NO_PUBKEY 7EA0A9C3F273FCD8
E: The repository 'https://download.docker.com/linux/ubuntu jammy InRelease' is not signed.原因: 配置了 Docker 官方 APT 软件源,但 APT 无法找到用于验证该软件源签名的公钥。这个错误与 Certbot 本身无关。
先查找 Docker 源配置文件:
sudo grep -RniE 'download.docker.com|mirrors.163.com/docker-ce' \
/etc/apt/sources.list /etc/apt/sources.list.d/如果服务器已配置可用的 Docker 镜像源,且当前只需要安装 Certbot,可以暂时禁用单独配置 Docker 官方源的文件。例如确认 /etc/apt/sources.list.d/docker.list 仅包含要禁用的条目后:
sudo mv /etc/apt/sources.list.d/docker.list \
/etc/apt/sources.list.d/docker.list.disabled
sudo apt updatedocker.list 是示例文件名,应以实际查询结果为准;如果同一文件还有其他重要源,不要直接整体禁用。此操作只修改 APT 软件源,不会停止已运行的 Docker 容器。
如果希望保留官方 Docker 源,应按 Docker 官方当前文档正确配置 /etc/apt/keyrings/docker.asc,并确保软件源使用 Signed-By 指向它:
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc仅下载密钥还不够:必须检查现有
.list或.sources中的signed-by/Signed-By配置,避免同一 Docker 仓库重复配置、密钥路径不一致等问题。不要通过关闭 APT 签名验证来绕过该错误。
三、申请 HTTPS 证书
先确认 Nginx 配置语法:
sudo nginx -t如果希望 Certbot 自动修改宿主机 Nginx 配置并启用 HTTPS:
sudo certbot --nginx -d example.cn如果仅申请证书,不希望 Certbot 修改 Nginx 配置:
sudo certbot certonly --nginx -d example.cn成功后,证书通常位于:
/etc/letsencrypt/live/example.cn/fullchain.pem
/etc/letsencrypt/live/example.cn/privkey.pemfullchain.pem:服务器证书及证书链。privkey.pem:私钥,禁止公开或随意复制。
如需手动配置宿主机 Nginx,可参考:
server {
listen 443 ssl;
server_name example.cn;
ssl_certificate /etc/letsencrypt/live/example.cn/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.cn/privkey.pem;
# 示例:反向代理到宿主机本地映射的 Docker 业务端口
location / {
proxy_pass http://127.0.0.1:8099;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
8099是示例端口,必须与实际应用端口一致。如果 Docker Nginx 已移除,应代理到当前仍在运行的真实服务端口,而不是照抄旧端口。
检查并重载 Nginx:
sudo nginx -t && sudo systemctl reload nginx四、配置 Certbot 自动续期
检查系统定时器:
sudo systemctl status certbot.timer实际输出包含:
certbot.timer - Run certbot twice daily
Loaded: loaded (...; enabled; ...)
Active: active (waiting)
Triggers: certbot.service说明定时器已启用,正在等待下一次执行。即使暂时没有满足续期条件的证书,Certbot 也会定期检查。
确保启用:
sudo systemctl enable --now certbot.timer4.1 模拟测试自动续期
执行:
sudo certbot renew --dry-run此次服务器输出:
Processing /etc/letsencrypt/renewal/example.cn.conf
Simulating renewal of an existing certificate for example.cn
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/example.cn/fullchain.pem (success)结论:模拟续期测试通过,定时器处于启用状态。 但 --dry-run 不代表生产证书已经实际更新;真正续期仍需等待证书进入 Certbot 判断的续期窗口,并确保届时域名验证条件仍然成立。
可进一步查看证书信息:
sudo certbot certificates五、证书更新后自动重载 Nginx
Certbot 的 Nginx 插件通常会处理相应的 Nginx 配置加载。如果希望增加明确的续期成功后重载动作,可使用 deploy hook:
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh >/dev/null <<'EOF_HOOK'
#!/bin/sh
/usr/sbin/nginx -t && /bin/systemctl reload nginx
EOF_HOOK
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh这个脚本在证书实际成功续期后执行,而不是每次定时器检查都执行。对于纯宿主机 Nginx 部署比较合适;如果 TLS 由 Docker 容器内的 Nginx 终止,就需要改成对应容器的证书挂载及重载方案,不能简单重载宿主机 Nginx。
测试 Nginx 重载脚本本身:
sudo /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh需要注意:普通 certbot renew --dry-run 并不等同于 deploy hook 也已经被验证。支持该参数的 Certbot 版本可使用 --run-deploy-hooks 配合测试;生产证书不会因此自动变成新证书。
六、日常维护与排查
# 查看自动续期任务
sudo systemctl status certbot.timer
# 查看 Certbot 已管理的证书与有效期
sudo certbot certificates
# 模拟续期
sudo certbot renew --dry-run
# 查看 Certbot 日志
sudo tail -n 100 /var/log/letsencrypt/letsencrypt.log
# 检查 Nginx 配置
sudo nginx -t
# 查看宿主机 80、443 端口占用
sudo ss -lntp | grep -E ':80 |:443 '常见排查方向:
80 端口验证失败:检查 DNS、安全组、防火墙、反向代理及其他服务的端口占用。
Nginx 配置测试失败:先执行
sudo nginx -t修复语法和文件路径,再申请或续期证书。续期成功但浏览器仍见旧证书:检查实际终止 TLS 的 Nginx/负载均衡器是否已重载,以及访问是否经过 CDN 或其他代理。
站点返回 403:通常是静态目录访问权限或 Nginx 根目录配置问题,证书申请成功并不能自动解决。
Docker 与宿主机 Nginx 冲突:一个宿主机 IP 的同一端口不能被两个服务同时直接绑定;建议统一由宿主机 Nginx 管理对外 HTTPS。
七、总结
在这次 Ubuntu 22.04 部署中,最终确认了以下结果:
Certbot 定时器
certbot.timer已启用,处于active (waiting)状态。certbot renew --dry-run成功模拟续期example.cn的证书。可以通过 deploy hook 在实际成功续期后自动重载宿主机 Nginx。
最重要的区别:自动续期机制已配置并通过模拟测试,不等于生产证书已经在本次测试中被实际续期。
