0
0
0

Ubuntu 22.04 使用 Certbot 为 Nginx 配置 HTTPS 与自动续期

2024-02-08
2026-10-08
文章摘要
|

本文记录在 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 update

docker.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.pem
  • fullchain.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.timer

4.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 '

常见排查方向:

  1. 80 端口验证失败:检查 DNS、安全组、防火墙、反向代理及其他服务的端口占用。

  2. Nginx 配置测试失败:先执行 sudo nginx -t 修复语法和文件路径,再申请或续期证书。

  3. 续期成功但浏览器仍见旧证书:检查实际终止 TLS 的 Nginx/负载均衡器是否已重载,以及访问是否经过 CDN 或其他代理。

  4. 站点返回 403:通常是静态目录访问权限或 Nginx 根目录配置问题,证书申请成功并不能自动解决。

  5. Docker 与宿主机 Nginx 冲突:一个宿主机 IP 的同一端口不能被两个服务同时直接绑定;建议统一由宿主机 Nginx 管理对外 HTTPS。

七、总结

在这次 Ubuntu 22.04 部署中,最终确认了以下结果:

  • Certbot 定时器 certbot.timer 已启用,处于 active (waiting) 状态。

  • certbot renew --dry-run 成功模拟续期 example.cn 的证书。

  • 可以通过 deploy hook 在实际成功续期后自动重载宿主机 Nginx。

最重要的区别:自动续期机制已配置并通过模拟测试,不等于生产证书已经在本次测试中被实际续期。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

评论