核心在于挂载整个证书目录(如/etc/letsencrypt/live/example.com)、开放其他用户读权限(chmod -R o+r)、配置绝对路径并配合--deploy-hook自动重载,确保续签后HTTPS实时生效且不中断。

在容器化环境中配置 Nginx HTTPS,核心不是“把证书塞进去”,而是让证书能随宿主机更新实时生效、Nginx 能稳定读取、重载不中断。关键在于挂载方式、权限控制和续签联动三者配合。
必须挂载整个证书目录,而不是单个 .pem 文件
Let’s Encrypt 等工具生成的 /etc/letsencrypt/live/example.com/ 下,fullchain.pem 和 privkey.pem 实际是符号链接,指向 ../../archive/ 中带时间戳的实际文件。如果只挂载这两个链接文件,续签后链接目标变更,容器内仍读旧路径——导致 HTTPS 500 或证书过期。
- 正确做法:挂载整个
live/example.com目录(或其父级letsencrypt),例如-v /etc/letsencrypt/live/example.com:/etc/nginx/ssl:ro - 更推荐:在宿主机建统一软链,如
/opt/nginx/ssl → /etc/letsencrypt/live/example.com,再挂载/opt/nginx/ssl,便于多域名切换
确保容器内 nginx 进程能读到证书
Nginx 容器默认以 UID 101(nginx 用户)运行,而宿主机证书通常属 root,且默认无其他用户读权限。若不开放,启动时会报 SSL_CTX_use_PrivateKey_file("/etc/nginx/ssl/privkey.pem") failed (SSL: error:0200100D:system library:fopen:Permission denied)。
- 执行
chmod -R o+r /etc/letsencrypt/live/example.com(开放其他用户只读) - SELinux 环境下需加标签:
chcon -Rt svirt_sandbox_file_t /etc/letsencrypt/live/example.com - 验证是否可读:
docker exec nginx ls -l /etc/nginx/ssl,确认两个 .pem 文件有o+r
Nginx 配置写法要匹配挂载路径
配置中不能用 ~/ssl/... 或相对路径;所有路径必须是绝对路径,且与 -v 挂载的目标路径完全一致。
- 容器内配置应写为:
ssl_certificate /etc/nginx/ssl/fullchain.pem;ssl_certificate_key /etc/nginx/ssl/privkey.pem; - 不要写成
/ssl/fullchain.pem或ssl/fullchain.pem,否则 Nginx 启动失败 - 建议将 HTTPS server 块单独放在
/etc/nginx/conf.d/ssl.conf,便于隔离维护
证书续签后必须主动重载 Nginx
Docker 的 bind mount 是实时同步的,宿主机证书一更新,容器内文件立刻变化。但 Nginx 不监听文件变动,不会自动 reload——必须外部触发。
- 最稳妥方式:在 Certbot 的
--deploy-hook中调用:certbot renew --deploy-hook "docker exec nginx nginx -s reload" - 避免用
kill -HUP或systemctl reload,容器内通常无 systemd - 测试重载是否成功:
docker exec nginx nginx -t && docker exec nginx nginx -s reload











