Docker Nginx HTTPS 实战:Let's Encrypt SSL 证书生成与自动续期
- [1. 前提条件](#1. 前提条件)
- [2. Certbot 安装](#2. Certbot 安装)
-
- [2.1 安装位置说明](#2.1 安装位置说明)
- [2.2 Ubuntu / Debian 安装](#2.2 Ubuntu / Debian 安装)
- [2.3 CentOS / RHEL 安装](#2.3 CentOS / RHEL 安装)
- [3. 证书生成](#3. 证书生成)
-
- [3.1 单域名证书](#3.1 单域名证书)
- [3.2 多域名证书](#3.2 多域名证书)
- [3.3 泛域名证书(DNS 验证)](#3.3 泛域名证书(DNS 验证))
- [4. 本地 Nginx 配置](#4. 本地 Nginx 配置)
-
- [4.1 HTTPS 配置](#4.1 HTTPS 配置)
- [4.2 HTTP 跳转与 ACME 验证](#4.2 HTTP 跳转与 ACME 验证)
- [5. Docker Nginx 部署与配置](#5. Docker Nginx 部署与配置)
-
- [5.1 Docker 部署命令](#5.1 Docker 部署命令)
- [5.2 Docker 内部 Nginx 配置](#5.2 Docker 内部 Nginx 配置)
- [6. 自动续签](#6. 自动续签)
-
- [6.1 测试续签(Dry Run)](#6.1 测试续签(Dry Run))
- [6.2 创建续签后执行脚本](#6.2 创建续签后执行脚本)
-
- [1️⃣ 通用目录](#1️⃣ 通用目录)
- [2️⃣ 创建脚本](#2️⃣ 创建脚本)
- [3️⃣ 设置可执行权限](#3️⃣ 设置可执行权限)
- [4️⃣ 测试脚本是否可执行](#4️⃣ 测试脚本是否可执行)
- [6.3 配置 Cron 定时任务](#6.3 配置 Cron 定时任务)
- [6.4 检查证书有效性](#6.4 检查证书有效性)
- [6.5 额外建议](#6.5 额外建议)
- [7. 常见问题与解决方案](#7. 常见问题与解决方案)
-
- [7.1 Webroot 验证失败 404](#7.1 Webroot 验证失败 404)
- [7.2 Docker 容器无法访问宿主机](#7.2 Docker 容器无法访问宿主机)
- [7.3 后端 API 返回 504 网关超时](#7.3 后端 API 返回 504 网关超时)
- [7.4 证书文件找不到](#7.4 证书文件找不到)
- [8. 总结](#8. 总结)
本文记录 从 Certbot 安装、证书生成、Nginx 配置、Docker 部署 HTTPS 到自动续签与常见问题 的完整实践经验。
文章严格区分 本地 Nginx 与 Docker Nginx 环境,每一步都提供详细说明和可直接执行的命令。

1. 前提条件
请确认以下条件满足:
-
已注册域名,并解析到服务器公网 IP
-
服务器 80/443 端口可访问(HTTP 和 HTTPS)
-
Linux 系统具备 sudo 权限
-
已安装 Nginx(本地或 Docker 容器)
-
(可选)DNS API 凭证,用于泛域名证书
2. Certbot 安装
2.1 安装位置说明
无论你运行 本地 Nginx 还是 Docker Nginx ,都需要在 运行证书生成和续签的机器上安装 Certbot。
-
对于本地 Nginx:Certbot 可直接修改配置
-
对于 Docker Nginx:Certbot 安装在宿主机或单独的 Certbot 容器,Nginx 容器只挂载证书
2.2 Ubuntu / Debian 安装
bash
sudo apt update
sudo apt install certbot python3-certbot-nginx -y
certbot --version
-
certbot:核心证书工具 -
python3-certbot-nginx:可选插件,用于本地 Nginx 自动配置 -
certbot --version:验证安装成功
2.3 CentOS / RHEL 安装
bash
sudo dnf install epel-release -y
sudo dnf install certbot python3-certbot-nginx -y
certbot --version
3. 证书生成
3.1 单域名证书
bash
sudo certbot certonly --webroot -w /opt/docker/nginx/html -d example.com
-
certonly:只生成证书,不修改 Nginx 配置 -
--webroot -w /opt/docker/nginx/htmll:指定 Webroot 目录,用于 HTTP 验证 -
/opt/docker/nginx/html:是宿主机目录, 而不是Docker 容器内目录 -
-d example.com:指定域名 -
证书生成路径:
/etc/letsencrypt/live/example.com/
3.2 多域名证书
bash
sudo certbot certonly --webroot -w /opt/docker/nginx/html -d example.com -d www.example.com -d api.example.com
- 一张证书覆盖多个域名,适合主域名 + 子域名组合
3.3 泛域名证书(DNS 验证)
bash
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/.secrets/cloudflare.ini -d "*.example.com"
-
泛域名必须使用 DNS TXT 验证
-
不可与普通域名证书混用在同一 server 块
-
支持多种 DNS API(Cloudflare、阿里云、腾讯云等)
4. 本地 Nginx 配置
4.1 HTTPS 配置
nginx
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
location / {
root /opt/html;
index index.html;
try_files $uri $uri/ /index.html;
}
}
4.2 HTTP 跳转与 ACME 验证
nginx
server {
listen 80;
server_name example.com;
location /.well-known/acme-challenge/ {
root /opt/html;
default_type text/plain;
try_files $uri =404;
}
location / {
return 301 https://$host$request_uri;
}
}
5. Docker Nginx 部署与配置
5.1 Docker 部署命令
bash
docker run -d \
--name nginx \
--restart always \
--network host \
-v /opt/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-v /opt/nginx/conf/conf.d:/etc/nginx/conf.d \
-v /opt/docker/nginx/html:/opt/html \
-v /etc/letsencrypt:/etc/letsencrypt:ro \
-v /opt/nginx/log:/var/log/nginx \
nginx:stable-alpine
-
--network host:容器使用宿主机网络,避免 127.0.0.1 问题 -
Webroot 挂载供 ACME 验证
-
/etc/letsencrypt挂载为只读 -
日志挂载到宿主机目录
5.2 Docker 内部 Nginx 配置
与本地 Nginx 相同,只需对应挂载路径:
-
Webroot:容器内
/opt/html -
证书路径:容器内
/etc/letsencrypt
6. 自动续签
6.1 测试续签(Dry Run)
-
执行 Certbot 模拟续签,不会实际修改证书:
bashsudo certbot renew --dry-run -
检查输出信息:
-
若显示
Congratulations, all simulated renewals succeeded→ 测试成功
-
若出现错误 → 检查 Webroot 路径、Nginx 配置或 DNS API 配置
-
确认 Webroot 可访问:
bashcurl http://example.com/.well-known/acme-challenge/testfile
6.2 创建续签后执行脚本
1️⃣ 通用目录
bash
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
2️⃣ 创建脚本
本地 Nginx:
bash
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh > /dev/null << 'EOF'
#!/bin/bash
nginx -s reload
EOF
Docker Nginx:
bash
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh > /dev/null << 'EOF'
#!/bin/bash
docker exec <容器名> nginx -s reload
EOF
⚠️ 将
<容器名>替换为实际 Docker 容器名,例如coupon-nginx
3️⃣ 设置可执行权限
bash
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
4️⃣ 测试脚本是否可执行
bash
sudo /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
-
正常情况下无输出即成功
-
如果报错 → 检查 Nginx 状态或 Docker 容器名
6.3 配置 Cron 定时任务
-
打开 crontab:
bashsudo crontab -e -
添加定时任务(每天凌晨 3 点执行续签并 reload):
cron0 3 * * * certbot renew --post-hook "/etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh" >> /var/log/certbot-renew.log 2>&1
可以根据实际环境选择执行哪一个脚本,本地或 Docker。
-
验证 Cron 服务状态:
bashsudo systemctl status cron # Ubuntu/Debian sudo systemctl status crond # CentOS/RHEL -
查看日志确认执行情况:
bashtail -f /var/log/certbot-renew.log
6.4 检查证书有效性
bash
sudo certbot certificates
-
输出证书到期时间,确认续签是否成功
-
对于 Docker,确认
/etc/letsencrypt挂载目录更新后,容器内 Nginx 能读取新证书
6.5 额外建议
-
自动续签脚本 必须有可执行权限 (
chmod +x) -
日志路径可自定义,建议定期查看
/var/log/certbot-renew.log -
对于 Docker Nginx,确保容器名与
docker exec命令一致 -
Cron 定时任务每天执行即可,Certbot 会判断证书到期才续签
7. 常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Webroot 验证失败 404 | .well-known/acme-challenge/ 未挂载 |
确认挂载路径 & Nginx location |
| Docker 内部访问宿主机失败 | Docker 默认桥接网络 | 使用 --network host 或宿主机内网 IP |
| 后端 API 504 | 后端绑定 IP 错误 / Nginx proxy_pass 配置 | Spring Boot server.address: 0.0.0.0 并确认 proxy_pass 正确 |
| 证书文件找不到 | Certbot 未生成或 Docker 挂载错误 | 生成证书并挂载 /etc/letsencrypt:/etc/letsencrypt:ro |
7.1 Webroot 验证失败 404
现象:
text
Failed authorization procedure. example.com (http-01): urn:ietf:params:acme:error:unauthorized
可能原因:
-
.well-known/acme-challenge/目录没有正确挂载到 Nginx 根目录 -
Nginx 配置里没有 location 定义,无法访问验证文件
-
防火墙或安全组阻挡 80 端口
排查步骤:
bash
# 检查 Webroot 是否存在
ls -l /opt/html/.well-known/acme-challenge/
# 检查 Nginx 是否能访问
curl http://example.com/.well-known/acme-challenge/testfile
解决方案:
-
确认宿主机 Webroot 挂载路径正确:
nginxlocation /.well-known/acme-challenge/ { root /opt/docker/nginx/html; default_type text/plain; try_files $uri =404; } -
如果 Docker Nginx,确保容器挂载 Webroot:
bash-v /opt/docker/nginx/html:/opt/html -
确保 80 端口可访问:
bashsudo ufw allow 80/tcp sudo firewall-cmd --add-port=80/tcp --permanent sudo firewall-cmd --reload
7.2 Docker 容器无法访问宿主机
现象:
- Docker Nginx 内部请求宿主机服务或验证时 404 或连接超时
原因:
- Docker 默认桥接网络,容器内访问
127.0.0.1指向容器本身,不是宿主机
解决方案:
-
使用 host 网络模式启动容器:
bashdocker run --network host ... -
或者使用宿主机内网 IP(例如 192.168.x.x)访问
-
挂载 Webroot 时确保路径正确映射到容器内
/opt/html
7.3 后端 API 返回 504 网关超时
现象:
- Nginx 代理后端请求超时,页面返回 504
可能原因:
-
后端应用绑定的 IP 不是 0.0.0.0,只监听本机 localhost
-
Nginx
proxy_pass配置指向错误地址或端口 -
后端服务未启动
排查步骤:
bash
# 检查后端监听地址
netstat -tulnp | grep 8080
# 本地 curl 测试
curl http://127.0.0.1:8080/api/test
解决方案:
-
Spring Boot 配置:
yamlserver: address: 0.0.0.0 port: 8080 -
Nginx proxy_pass 配置:
nginxlocation /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } -
确保后端服务启动,并能在宿主机访问
7.4 证书文件找不到
现象:
- Nginx 启动报错:
cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem"
可能原因:
-
Certbot 没有生成证书
-
Docker 容器没有挂载证书目录
-
权限问题,Nginx 无法读取文件
排查步骤:
bash
# 检查证书是否生成
ls -l /etc/letsencrypt/live/example.com/
# 容器内检查挂载
docker exec nginx ls -l /etc/letsencrypt/live/example.com/
解决方案:
-
生成证书:
bashsudo certbot certonly --webroot -w /opt/docker/nginx/html -d example.com -
Docker 容器挂载证书:
bash-v /etc/letsencrypt:/etc/letsencrypt:ro -
确认权限:
bashsudo chown -R root:root /etc/letsencrypt sudo chmod -R 755 /etc/letsencrypt/live -
证书生成后 reload Nginx:
-
本地 Nginx:
bashnginx -s reload -
Docker Nginx:
bashdocker exec nginx nginx -s reload
8. 总结
-
所有环境都需安装 Certbot,但 Docker 不在容器内安装
-
Webroot 模式最适合 Docker Nginx
-
泛域名证书适合多子域名或动态子域场景
-
Docker Nginx 推荐
--network host避免 127.0.0.1 访问问题 -
配置 HSTS、安全头、静态资源缓存提升安全和性能
-
自动续期 + Nginx reload 保证证书长期有效
-
单域名、多域名、泛域名证书可灵活组合