Docker Nginx HTTPS 实战:Let’s Encrypt SSL 证书生成与自动续期

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 到自动续签与常见问题 的完整实践经验。

文章严格区分 本地 NginxDocker 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)

  1. 执行 Certbot 模拟续签,不会实际修改证书

    bash 复制代码
    sudo certbot renew --dry-run
  2. 检查输出信息:

  • 若显示 Congratulations, all simulated renewals succeeded → 测试成功

  • 若出现错误 → 检查 Webroot 路径、Nginx 配置或 DNS API 配置

  1. 确认 Webroot 可访问:

    bash 复制代码
    curl 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 定时任务

  1. 打开 crontab:

    bash 复制代码
    sudo crontab -e
  2. 添加定时任务(每天凌晨 3 点执行续签并 reload):

    cron 复制代码
    0 3 * * * certbot renew --post-hook "/etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh" >> /var/log/certbot-renew.log 2>&1

可以根据实际环境选择执行哪一个脚本,本地或 Docker。

  1. 验证 Cron 服务状态:

    bash 复制代码
    sudo systemctl status cron      # Ubuntu/Debian
    sudo systemctl status crond     # CentOS/RHEL
  2. 查看日志确认执行情况:

    bash 复制代码
    tail -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

可能原因:

  1. .well-known/acme-challenge/ 目录没有正确挂载到 Nginx 根目录

  2. Nginx 配置里没有 location 定义,无法访问验证文件

  3. 防火墙或安全组阻挡 80 端口

排查步骤:

bash 复制代码
# 检查 Webroot 是否存在
ls -l /opt/html/.well-known/acme-challenge/

# 检查 Nginx 是否能访问
curl http://example.com/.well-known/acme-challenge/testfile

解决方案:

  1. 确认宿主机 Webroot 挂载路径正确:

    nginx 复制代码
    location /.well-known/acme-challenge/ {
        root /opt/docker/nginx/html;
        default_type text/plain;
        try_files $uri =404;
    }
  2. 如果 Docker Nginx,确保容器挂载 Webroot:

    bash 复制代码
    -v /opt/docker/nginx/html:/opt/html
  3. 确保 80 端口可访问:

    bash 复制代码
    sudo 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 指向容器本身,不是宿主机

解决方案:

  1. 使用 host 网络模式启动容器:

    bash 复制代码
    docker run --network host ...
  2. 或者使用宿主机内网 IP(例如 192.168.x.x)访问

  3. 挂载 Webroot 时确保路径正确映射到容器内 /opt/html


7.3 后端 API 返回 504 网关超时

现象:

  • Nginx 代理后端请求超时,页面返回 504

可能原因:

  1. 后端应用绑定的 IP 不是 0.0.0.0,只监听本机 localhost

  2. Nginx proxy_pass 配置指向错误地址或端口

  3. 后端服务未启动

排查步骤:

bash 复制代码
# 检查后端监听地址
netstat -tulnp | grep 8080

# 本地 curl 测试
curl http://127.0.0.1:8080/api/test

解决方案:

  1. Spring Boot 配置

    yaml 复制代码
    server:
      address: 0.0.0.0
      port: 8080
  2. Nginx proxy_pass 配置

    nginx 复制代码
    location /api/ {
        proxy_pass http://127.0.0.1:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
  3. 确保后端服务启动,并能在宿主机访问


7.4 证书文件找不到

现象:

  • Nginx 启动报错:cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem"

可能原因:

  1. Certbot 没有生成证书

  2. Docker 容器没有挂载证书目录

  3. 权限问题,Nginx 无法读取文件

排查步骤:

bash 复制代码
# 检查证书是否生成
ls -l /etc/letsencrypt/live/example.com/

# 容器内检查挂载
docker exec nginx ls -l /etc/letsencrypt/live/example.com/

解决方案:

  1. 生成证书:

    bash 复制代码
    sudo certbot certonly --webroot -w /opt/docker/nginx/html -d example.com
  2. Docker 容器挂载证书:

    bash 复制代码
    -v /etc/letsencrypt:/etc/letsencrypt:ro
  3. 确认权限:

    bash 复制代码
    sudo chown -R root:root /etc/letsencrypt
    sudo chmod -R 755 /etc/letsencrypt/live
  4. 证书生成后 reload Nginx:

  • 本地 Nginx:

    bash 复制代码
    nginx -s reload
  • Docker Nginx:

    bash 复制代码
    docker exec nginx nginx -s reload

8. 总结

  1. 所有环境都需安装 Certbot,但 Docker 不在容器内安装

  2. Webroot 模式最适合 Docker Nginx

  3. 泛域名证书适合多子域名或动态子域场景

  4. Docker Nginx 推荐 --network host 避免 127.0.0.1 访问问题

  5. 配置 HSTS、安全头、静态资源缓存提升安全和性能

  6. 自动续期 + Nginx reload 保证证书长期有效

  7. 单域名、多域名、泛域名证书可灵活组合

相关推荐
八宝粥大朋友2 小时前
OpenSSL构建android 脚本
android·ssl
草莓熊Lotso2 小时前
Linux 命令行参数与环境变量实战:从基础用法到底层原理
linux·运维·服务器·开发语言·数据库·c++·人工智能
magnetotell2 小时前
Postgresql 在Windows10 docker上部署踩坑教程
运维·docker·容器
草莓熊Lotso2 小时前
Qt 控件核心入门:从基础认知到核心属性实战(含资源管理)
运维·开发语言·c++·人工智能·后端·qt·架构
张太行_11 小时前
Linux静态库:多模块高效管理
linux·运维·服务器
2501_9160088912 小时前
iOS 上架需要哪些准备,账号、Bundle ID、证书、描述文件、安装测试及上传
android·ios·小程序·https·uni-app·iphone·webview
wgl66652012 小时前
Linux---基础IO!
linux·运维·服务器
Ancelin安心12 小时前
kali-dirsearch的使用
linux·运维·服务器·python·计算机网络·web安全·网络安全
jun_bai13 小时前
python+Java的网盘程序升级版。无感知备份文档,保护数据资产利器。
运维·服务器