Django 从入门到精通:知行博客实战(6.1) · 第 32 / 36 节

Nginx、HTTPS 与生产配置

吴秀峰 3 次阅读 0 条评论 ↓

学习目标

为真实域名启用 HTTPS,理解代理头和安全 Cookie,分离静态与媒体响应,运行部署检查并明确解决剩余问题。

为什么本机能打开不等于已经上线

生产环境需要稳定域名、证书、邮件服务、备份和监控。DEBUG 必须关闭,ALLOWED_HOSTS 必须限制主机;错误的协议转发会让密码重置链接变成 HTTP,或造成 HTTPS 重定向循环。只有受控 Nginx 能访问 Web,且 Nginx 覆盖客户端传来的转发头,才能信任 SECURE_PROXY_SSL_HEADER。

静态 CSS 可缓存,用户媒体需要 nosniff 与隔离策略。当前允许的图片格式经过服务端验证;Nginx 不执行媒体内容。账号入口限流是起点,不等于全面防刷,多个代理或 CDN 前的真实 IP 识别必须按可信链路配置。

具体怎么做

  1. 准备指向服务器的域名与有效证书。证书签发依赖你的域名和托管环境,可通过已有宝塔面板或受信任 ACME 客户端完成;私钥仅留在服务器。
  2. 将 deploy/nginx.https.conf 中两处 blog.example.com 换成真实域名。证书目录必须包含 fullchain.pem 和 privkey.pem。
  3. 在 .env 设置 DJANGO_ALLOWED_HOSTS 为 你的域名,127.0.0.1,localhost,其中回环地址供容器健康检查使用;设置 TLS_CERT_DIR 为实际证书目录,填写可用 SMTP 和发件人。
  4. 使用 HTTPS 覆盖文件;它增加 80/443 端口,保留原本仅回环访问的 8010 调试入口。
docker compose -f compose.yaml -f compose.https.yaml config --quiet
docker compose -f compose.yaml -f compose.https.yaml up -d --force-recreate web nginx
docker compose -f compose.yaml -f compose.https.yaml exec -T nginx nginx -t
docker compose -f compose.yaml -f compose.https.yaml exec -T web python manage.py check --deploy

后续部署、备份和恢复脚本也要使用同一组 Compose 配置。Linux 运维终端可执行 export COMPOSE_FILE=compose.yaml:compose.https.yaml 后运行脚本,避免某次发布意外退回 HTTP;或把该变量放在部署专用环境中。

本章新增或替换的完整文件

以下路径均相对于练习项目根目录。替换同名文件的全部内容;未列出的文件保持上一章版本。

compose.https.yaml

services:
  web:
    environment:
      DJANGO_HTTPS: "1"
      DJANGO_HSTS_SECONDS: "3600"
  nginx:
    ports: ["80:80", "443:443"]
    volumes:
      - ./deploy/nginx.https.conf:/etc/nginx/conf.d/default.conf:ro
      - ${TLS_CERT_DIR:?请设置 TLS_CERT_DIR}:/etc/nginx/certs:ro

config/production.py

import os
os.environ["DJANGO_DEBUG"] = "0"
from .settings import *
if os.environ.get("DB_ENGINE") != "mysql":
    raise ImproperlyConfigured("本教程的生产配置要求独立 MySQL 数据库")
DEBUG = False

# 仅让受控 Nginx 访问 Gunicorn;Nginx 必须覆盖来自客户端的转发头。
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
HTTPS_ENABLED = os.environ.get("DJANGO_HTTPS", "0") == "1"
SECURE_SSL_REDIRECT = HTTPS_ENABLED
SECURE_REDIRECT_EXEMPT = [r"^health/$"]
SESSION_COOKIE_SECURE = HTTPS_ENABLED
CSRF_COOKIE_SECURE = HTTPS_ENABLED
SECURE_HSTS_SECONDS = int(os.environ.get("DJANGO_HSTS_SECONDS", "0")) if HTTPS_ENABLED else 0
SECURE_HSTS_INCLUDE_SUBDOMAINS = False
SECURE_HSTS_PRELOAD = False

deploy/nginx.https.conf

limit_req_zone $binary_remote_addr zone=auth:10m rate=5r/m;
server {
    listen 80;
    server_name blog.example.com;
    return 308 https://blog.example.com$request_uri;
}
server {
    listen 443 ssl;
    server_name blog.example.com;
    ssl_certificate /etc/nginx/certs/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    client_max_body_size 3m;
    add_header X-Content-Type-Options nosniff always;
    location /static/ { alias /app/staticfiles/; expires 7d; }
    location /media/ {
        alias /app/media/;
        add_header X-Content-Type-Options nosniff always;
        add_header Content-Security-Policy "default-src 'none'; sandbox" always;
    }
    location ~ /\. { deny all; }
    location /accounts/ {
        limit_req zone=auth burst=10 nodelay;
        limit_req_status 429;
        proxy_pass http://web:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    location / {
        proxy_pass http://web:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 65s;
    }
}

如何确认成功

浏览器从 HTTP 自动跳到 HTTPS,证书域名正确;登录和发文章不会循环跳转;浏览器 Cookie 中会话和 CSRF 均带 Secure;重置邮件使用正确的 HTTPS 域名。使用真实收件箱验证邮件送达,不只看 SMTP 接受结果。

check --deploy 中的邮件后端错误必须通过真实 SMTP 解决,不能用 silenced checks 隐藏。HSTS 先设置较短时间,确认所有相关访问长期支持 HTTPS 后再提升;是否覆盖子域和预加载取决于你是否控制全部子域,不要机械开启。

练习:写一份上线验收记录,包含域名、证书到期、回退方式、数据库卷、媒体卷、SMTP 和备份位置。不要在记录中写明文密码。

常见问题

502? 查看 Nginx 是否能连接 web:8000,核对服务日志和启动状态。上传 413? 请求超过 Nginx 上限,不要盲目加大,应与表单限制一致。启用 Secure Cookie 后本地 HTTP 登录失效? 这是保护机制,生产使用 HTTPS;本地使用基础 Compose 的 HTTP 配置。宝塔部署如何对应? 本站仓库已有 docs/deploy-baota.md 和 deploy/baota/,其环境加载方式与本练习 Docker 方案不同,应按对应文档操作。

官方参考

把学习连起来

登录后可保存阅读位置、标记章节完成,并在其他设备继续学习。

登录并保存学习进度 →
联系站长

微信:VIPdjango。技术问题建议先在 社区讨论 中交流,方便更多人参与和查阅。

章节讨论 0