使用 docker-compose 启动的 nginx 容器证书过期
解决方案:重新申请并部署新的 SSL 证书
我的方案:使用 Let's Encrypt + Certbot(更自动化)
1:运行 certbot 生成证书
假设域名为:mydomain.com,登录服务器用户 u1,nginx容器名:nginx-web
有公网 IP 和域名解析。
由于我80端口已经被nginx占用,使用 --webroot 插件(最推荐!无需停 Nginx)
如果你的 Nginx 已经在提供网站服务,可以利用现有 Web 目录完成验证。
1.1:确保 Nginx 能正确响应 /.well-known/acme-challenge/ 路径在你的 Nginx 配置中添加(或确认已有):
nginx
server {
listen 80;
server_name mydomain.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot; # 或你指定的 webroot 路径
}
location / {
# 你的正常网站配置
}
}
1.2:在宿主机创建 challenge 目录并挂载到容器
bash
sudo mkdir -p /var/www/certbot
1.3:如果你用 docker-compose.yml,确保 Nginx 容器挂载了这个目录:
yaml
volumes:
- /var/www/certbot:/var/www/certbot:ro
修改了配置,需要重启容器
bash
docker-compose up -d --force-recreate nginx-web
1.4:运行 certbot 使用 --webroot
bash
sudo certbot certonly \
--webroot \
-w /var/www/certbot \
-d mydomain.com
✅ 这样 Certbot 会把验证文件写入 /var/www/certbot/.well-known/acme-challenge/,Nginx 会正常响应,无需停服务!
证书路径通常为:
/etc/letsencrypt/live/mydomain.com/fullchain.pem/etc/letsencrypt/live/mydomain.com/privkey.pem
然后挂载到 Docker 即可。
💡 Let's Encrypt 证书有效期 90 天,但可以自动续期(配合 cron 或 watchtower)。
1.5 验证新证书是否生效
部署后再次测试:
bash
curl -v https://mydomain.com --resolve mydomain.com:443:127.0.0.1
也可检查证书日期:
bash
openssl x509 -in /home/u1/docker/nginx/certs/fullchain.pem -noout -dates
输出应类似:
bash
notBefore=Nov 20 00:00:00 2025 GMT
notAfter=Feb 18 23:59:59 2026 GMT
临时绕过(仅调试用)
如果你只是想临时测试服务是否正常,可以用:
bash
curl -k https://localhost
2:创建一个由 root 执行的复制脚本
因为我当前登录服务器的用户 u1 没有root权限。
推荐方法:让 certbot renew 通过 --deploy-hook 自动复制证书(由 root 执行)
2.1:创建一个由 root 执行的复制脚本
bash
sudo nano /usr/local/bin/copy-ssl-to-nginx.sh
内容如下:
bash
#!/bin/bash
# 复制证书到 u1 有权限的目录
cp -L /etc/letsencrypt/live/mydomain.com/fullchain.pem /home/u1/docker/nginx/cert/
cp -L /etc/letsencrypt/live/mydomain.com/privkey.pem /home/u1/docker/nginx/cert/
# 设置正确权限(确保 u1 可读)
chown u1:u1 /home/u1/docker/nginx/cert/{fullchain.pem,privkey.pem}
chmod 644 /home/u1/docker/nginx/cert/fullchain.pem
chmod 600 /home/u1/docker/nginx/cert/privkey.pem
# 重载 Nginx(使用 docker-compose, nginx-web是容器名)
# /usr/local/bin/docker-compose 是 docker-compose 的绝对路径
cd /home/u1/docker/compose-yml || exit 1
sudo -u u1 /usr/local/bin/docker-compose exec -T nginx-web nginx -s reload
执行写入命令:Ctrl+W
执行退出命令:Ctrl+O
保存后,赋予执行权限:
bash
sudo chmod +x /usr/local/bin/copy-ssl-to-nginx.sh
2.1.1:找到 docker-compose 的绝对路径
以你的普通用户身份运行:
bash
which docker-compose
常见输出示例:
/usr/local/bin/docker-compose/home/u1/.local/bin/docker-compose/usr/bin/docker-compose
2.2:配置 Certbot 使用 --deploy-hook(推荐)或 --post-hook
✅ --deploy-hook :仅在证书实际更新时才执行(比 --post-hook 更高效)
修改 Certbot 的 renewal 配置(推荐)
找到你的域名对应的 renewal 配置:
bash
sudo nano /etc/letsencrypt/renewal/mydomain.com.conf
在 [renewalparams] 段落下添加:
bash
deploy_hook = /usr/local/bin/copy-ssl-to-nginx.sh
保存退出。
📝 示例片段:
ini[renewalparams] ... deploy_hook = /usr/local/bin/copy-ssl-to-nginx.sh
2.3: 最终自动化流程(无需你的用户参与复制)
- 系统定时任务运行:
sudo certbot renew - 如果证书需要更新:
- Certbot 获取新证书(root 权限)
- 自动触发
deploy_hook - root 执行脚本:复制证书 → 改权限 → 重载 Nginx(以
cm1身份调用 docker-compose)
- 你的网站无缝使用新证书 ✅
3: 设置 root 的定时任务(推荐)
3.1: 设置定时任务
bash
sudo crontab -e
添加:
bash
0 3 * * * /usr/bin/certbot renew --quiet
3.2: ✅ 验证
手动触发一次(测试):
bash
sudo certbot renew --force-renewal --deploy-hook "/usr/local/bin/copy-ssl-to-nginx.sh"
然后检查:
bash
ls -l /home/u1/docker/nginx/cert/
cat /home/u1/docker/nginx/cert/fullchain.pem # 应该能读