TLS (HTTPS) 部署指南
本文档描述了 Classroom Manager 生产环境部署中 HTTPS 的实现方式,使用 Nginx 作为 TLS 终端和反向代理,运行在 Docker Compose 技术栈中。
架构概览
在生产环境中,一个专用的 Nginx 容器负责:
- 在 443 端口(HTTPS)终止 TLS,并提供证书和私钥服务。
- 将构建好的前端作为静态文件从
/usr/share/nginx/html提供服务,并通过try_files支持 SPA 路由。 - 将后端请求(Django/Gunicorn)反向代理到内部上游
backend:8000。 - 将常用应用路径转发到后端:
/api/、/media/、/admin/和/static/。
从 Compose 的角度来看:
- Nginx 服务发布主机端口 80 和 443。
- Nginx 以只读卷挂载生产配置和证书目录。
- Nginx 依赖后端容器并加入同一 Docker 网络以进行服务发现。
文件和路径
Nginx 配置
Nginx 从以下位置加载生产虚拟主机配置:
- 主机路径:
./nginx/nginx.conf - 容器路径:
/etc/nginx/conf.d/default.conf(只读)
证书目录
证书期望位于:
- 主机路径:
./nginx/certs/ - 容器路径:
/etc/nginx/certs/(只读)
并在 Nginx 中引用为:
/etc/nginx/certs/fullchain.pem(证书链)/etc/nginx/certs/privkey.pem(私钥)
前提条件
你必须拥有有效的 TLS 证书和私钥对,位于以下路径:
./nginx/certs/fullchain.pem./nginx/certs/privkey.pem
确保主机上的文件权限合适(私钥应受限访问):
chmod 600 ./nginx/certs/privkey.pemchmod 644 ./nginx/certs/fullchain.pem
更新 Nginx 配置中的
server_name以匹配你的真实域名。
证书获取
方案 A:使用受信任的 CA(推荐)
从受信任的 CA 获取证书(例如通过 ACME/Let's Encrypt),在主机(或专用的证书管理容器)上获取,然后将生成的文件复制/软链接到 ./nginx/certs/:
- 将完整证书链放置为
./nginx/certs/fullchain.pem - 将私钥放置为
./nginx/certs/privkey.pem
续期后,重新加载 Nginx 以使其加载新文件:
docker compose -f docker-compose.prod.yml exec nginx nginx -t
docker compose -f docker-compose.prod.yml exec nginx nginx -s reload方案 B:自签名证书(仅用于开发/内部测试)
WARNING
自签名证书会导致浏览器警告,不应在公共生产环境中使用,但可用于快速功能验证。
mkdir -p ./nginx/certs
openssl req -x509 -nodes -newkey rsa:2048 -days 365 \
-keyout ./nginx/certs/privkey.pem \
-out ./nginx/certs/fullchain.pem \
-subj "/CN=localhost"Nginx TLS 配置(当前行为)
TLS 监听
服务器块在 443 端口启用 SSL 监听。
证书
Nginx 从挂载的证书目录加载证书链和密钥。
协议和会话设置
配置启用了 TLS 1.2 和 TLS 1.3,使用 SSL 会话缓存,设置会话超时,并禁用会话票据。
路由行为
/从/usr/share/nginx/html提供 SPA 前端服务,对于客户端路由回退到/index.html。/api/、/media/、/admin/被反向代理到上游,并包含标准转发头(包括X-Forwarded-Proto)。/static/同样被代理到后端。
加固和生产环境建议
添加 HTTP(端口 80)到 HTTPS 的重定向
如果暴露了 80 端口,添加一个单独的服务器块将所有 HTTP 流量重定向到 HTTPS:
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}使用真实域名并考虑 HSTS
将 server_name localhost; 替换为你的实际域名。确认 HTTPS 稳定后,考虑添加 HSTS:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;DANGER
只有在你确定 HTTPS 在你的域名上正确工作时才启用 HSTS。
添加现代安全头(推荐)
典型的基线配置:
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header Referrer-Policy strict-origin-when-cross-origin always;验证反向代理后面的 Django 设置
由于 Nginx 转发了 X-Forwarded-Proto,确保 Django 配置为信任该头,以便它能正确检测安全请求并生成 HTTPS URL。常见设置包括:
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")CSRF_TRUSTED_ORIGINS = ["https://example.com"]SESSION_COOKIE_SECURE = TrueCSRF_COOKIE_SECURE = True
运维检查清单
上线前
确认证书文件存在:
./nginx/certs/fullchain.pem./nginx/certs/privkey.pem
确认 Nginx 正常加载:
docker compose -f docker-compose.prod.yml exec nginx nginx -t- 确认 HTTPS 可达性:
curl -vkI https://YOUR_DOMAIN/
curl -vkI https://YOUR_DOMAIN/api/上线后
- 启用自动证书续期(如果使用 ACME)。
- 续期后重新加载 Nginx。
- 定期从外部网络验证 TLS 和响应头。