Appearance
Docker 环境中使用 Nginx 和 Let's Encrypt 配置 HTTPS
概述
在现代 Web 开发中,HTTPS 已经成为网站的标准配置。本教程将指导您在 Docker 环境中使用 Nginx 作为 Web 服务器,结合 Certbot 和 Let's Encrypt 来实现 HTTPS 安全连接的完整配置流程。
- 使用 Docker Compose 启动两个容器,一个是 Nginx,另一个是 Certbot。
- 使用 Certbot 自动获取和更新 SSL 证书。
- 通过 Docker 卷将 Certbot 获取的证书文件夹挂载到 Nginx 容器中。
- 重启 Certbot 容器自动续期证书。
步骤一:配置 Nginx 服务器
基础 Docker Compose 配置
首先创建一个基础的 Nginx 服务:
yaml
version: "3"
services:
ssl-nginx:
image: nginx:latest
ports:
- 80:80 # HTTP 端口
- 443:443 # HTTPS 端口
restart: always
volumes:
- ./nginx/conf/:/etc/nginx/conf.d/:ro
- ./certbot/www:/certbot/www:ro # Certbot 验证文件夹
- ./certbot/conf/:/etc/nginx/ssl/:ro # Certbot 证书文件夹关联到 Nginx 容器内的 ssl 目录Nginx 配置文件
在 ./nginx/conf/ 目录下创建配置文件:
nginx
# HTTP 配置 - 用于重定向和证书验证
server {
listen 80;
server_name example.com www.example.com;
server_tokens off;
# 这个配置允许 Certbot 通过 HTTP 协议验证域名所有权,是获取 SSL 证书的必要步骤。
location /.well-known/acme-challenge/ {
root /certbot/www; # 返回 Certbot 验证文件
}
# 其他所有请求重定向到 HTTPS
location / {
return 301 https://example.com$request_uri;
}
}
# HTTPS 配置 - 安全连接处理
server {
listen 443 ssl http2;
server_name example.com;
# SSL 证书配置
ssl_certificate /etc/nginx/ssl/live/example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/example.com/privkey.pem;
# SSL 安全配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_prefer_server_ciphers on;
location / {
# 这里配置应用
root /var/www/html;
index index.html index.htm;
try_files $uri $uri/ =404;
}
}步骤二:配置 Certbot 获取证书
添加 Certbot 服务
更新 Docker Compose 文件,添加 Certbot 服务:
yaml
version: "3"
services:
ssl-nginx:
image: nginx:latest
ports:
- 80:80
- 443:443
restart: always
volumes:
- ./nginx/conf/:/etc/nginx/conf.d/:ro
- ./certbot/www:/certbot/www:ro
- ./certbot/conf/:/etc/nginx/ssl/:ro
certbot:
image: certbot/certbot:latest
volumes:
- ./certbot/www/:/var/www/certbot/:rw # 将验证文件通共享目录的方式关联到 Nginx 容器
- ./certbot/conf/:/etc/letsencrypt/:rw # 将证书文件通过挂载共享目录的方式关联到 Nginx 容器权限说明:
:ro(read-only):容器只能读取,不能修改:rw(read-write):容器可以读取和写入
测试证书获取
启动服务并测试证书获取(干运行模式):
bash
# 启动 Nginx 服务, 确保可以访问 HTTP 端口
docker compose up -d ssl-nginx
# 测试证书获取(干运行模式:不会实际创建证书,测试配置有效性)
docker compose run --rm certbot certonly \
--webroot \
--webroot-path /var/www/certbot/ \
--dry-run \
-d example.com如果看到 "The dry run was successful" 消息,说明配置正确。
为什么使用 --dry-run?
--dry-run选项用于模拟证书获取过程,确保配置正确而不实际创建证书。这有助于在正式申请前发现潜在问题。- Let's Encrypt 对证书申请有严格的速率限制:每个域名每周最多申请 5 次失败, 使用
--dry-run可以避免因配置错误而浪费申请次数。
| 项目 | 测试命令 | 正式命令 |
|---|---|---|
--dry-run 参数 | ✅ 包含 | ❌ 不包含 |
| 域名数量 | 通常只测试一个域名 | 可以包含多个域名 |
| 证书文件 | 🚫 不会创建实际证书 | ✅ 创建真实证书文件 |
| Let's Encrypt 配额 | 🚫 不计入申请次数限制 | ✅ 计入申请次数限制 |
这样的设计确保了在正式申请证书之前,所有配置都是正确的,避免了因配置错误而触发 Let's Encrypt 的速率限制。
正式获取证书
确认测试通过后,获取真实证书:
bash
# 获取正式证书
docker compose run --rm certbot certonly \
--webroot \
--webroot-path /var/www/certbot/ \
-d example.com \
-d www.example.com证书获取成功后,证书文件将保存在 `./certbot/conf/live/example.com/` 目录中。
为什么用 docker compose run 而不是 docker run?
docker compose run 会自动继承 docker-compose.yml 中为 certbot 服务定义的完整环境 (包括卷挂载、网络、环境变量、依赖关系等)。若用 docker run,需手动复制所有参数(例如冗长的挂载参数),极易出错。
证书申请过程会调用
/.well-known/acme-challenge/进行域名验证。因此必须先通过docker compose up -d ssl-nginx确保服务已就绪。docker compose run certbot会临时启动一个新容器执行命令,与 Compose 文件中 certbot 的容器是否启动无关。
步骤三:重载 Nginx 配置
重启服务
bash
# 重启所有服务
docker compose restart
# 或者仅重载 Nginx 配置(无服务中断)
docker compose exec ssl-nginx nginx -s reload验证 HTTPS 配置
访问您的网站验证 HTTPS 是否正常工作:
bash
# 检查证书状态
curl -I https://example.com
# 检查 SSL 评级(可选)
curl -s "https://api.ssllabs.com/api/v3/analyze?host=example.com" | jq步骤四:证书自动续期
Let's Encrypt 证书特点
WARNING
证书有效期 Let's Encrypt 证书有效期仅为 90 天,需要定期续期以避免证书过期。
手动续期
bash
# 续期所有即将过期的证书
docker compose run --rm certbot renew
# 续期后重载 Nginx 配置
docker compose exec webserver nginx -s reload自动化续期脚本
创建自动续期脚本:
bash
#!/bin/bash
# 自动续期 SSL 证书脚本
cd /path/to/your/project
echo "开始检查证书续期..."
# 尝试续期证书
docker compose run --rm certbot renew
# 重载 Nginx 配置
if [ $? -eq 0 ]; then
echo "证书续期成功,重载 Nginx 配置..."
docker compose exec webserver nginx -s reload
echo "Nginx 配置重载完成"
else
echo "证书续期失败"
exit 1
fi
echo "证书续期检查完成"bash
#!/bin/bash
# 设置定时任务
# 每月 1 号凌晨 2 点执行证书续期
echo "0 2 1 * * /path/to/your/scripts/renew-certs.sh >> /var/log/ssl-renew.log 2>&1" | crontab -
echo "定时任务设置完成"设置 Cron 定时任务
bash
# 编辑 crontab
crontab -e
# 添加以下行(每月 1 号凌晨 2 点执行)
0 2 1 * * /path/to/your/scripts/renew-certs.sh >> /var/log/ssl-renew.log 2>&1:::
故障排除
常见问题及解决方案
点击查看常见问题
问题 1:证书获取失败
bash
# 检查域名 DNS 解析
nslookup example.com
# 检查防火墙端口
sudo ufw status
sudo ufw allow 80
sudo ufw allow 443
# 检查 Nginx 配置
docker compose exec webserver nginx -t问题 2:证书验证路径不可访问
bash
# 检查文件权限
ls -la ./certbot/www/
# 测试验证路径
curl http://example.com/.well-known/acme-challenge/test问题 3:SSL 握手失败
bash
# 检查 SSL 配置
openssl s_client -connect example.com:443 -servername example.com
# 检查证书有效性
openssl x509 -in ./certbot/conf/live/example.com/fullchain.pem -text -noout日志检查
bash
# 查看 Nginx 日志
docker compose logs ssl-nginx
# 查看 Certbot 日志
docker compose logs certbot
# 查看实时日志
docker compose logs -f ssl-nginx