فصل ۸: تست، استقرار و پروژه‌ی پایانی

استقرار (۲): nginx، static با WhiteNoise، media، HTTPS و check --deploy

لایه‌ی جلویی و امنیت نهایی

nginx درخواست‌ها را از اینترنت می‌گیرد، HTTPS را مدیریت می‌کند، فایل‌های media را مستقیم از دیسک سرو می‌کند و بقیه را از طریق سوکت به gunicorn می‌دهد. برای static دو راه داریم: nginx مستقیم، یا WhiteNoise که فایل‌ها را فشرده و با نام هش‌دار از خود جنگو سرو می‌کند و در پشت CDN یا nginx بهترین هدرهای کش را می‌گذارد.

WhiteNoise

# pip install whitenoise
MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "whitenoise.middleware.WhiteNoiseMiddleware",        # بلافاصله بعد از Security
    # ...
]
STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "staticfiles"
STATICFILES_DIRS = [BASE_DIR / "static"]
STORAGES = {
    "default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
    "staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"},
}

nginx

# /etc/nginx/sites-available/carpet
upstream carpet_app { server unix:/run/carpet.sock fail_timeout=0; }

server {
    listen 80;
    server_name example.ir www.example.ir;
    client_max_body_size 10M;

    location /media/ {
        alias /srv/carpet/app/media/;
        expires 30d;
    }
    location /protected/ {
        internal;                                   # فقط با X-Accel-Redirect
        alias /srv/carpet/private/;
    }
    location / {
        proxy_pass http://carpet_app;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 60s;
    }
}
sudo ln -s /etc/nginx/sites-available/carpet /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.ir -d www.example.ir

certbot گواهی Let's Encrypt را می‌گیرد، بلوک listen 443 ssl را به کانفیگ اضافه می‌کند و تمدید خودکار را با یک systemd timer تنظیم می‌کند.

تنظیمات امنیتی production

تنظیممقداراثر
DEBUGFalseعدم نمایش جزئیات خطا
SECURE_PROXY_SSL_HEADER("HTTP_X_FORWARDED_PROTO", "https")جنگو بفهمد درخواست HTTPS بوده
SECURE_SSL_REDIRECTTrueریدایرکت HTTP به HTTPS
SESSION_COOKIE_SECURE / CSRF_COOKIE_SECURETrueکوکی‌ها فقط روی HTTPS
SECURE_HSTS_SECONDSابتدا 3600، بعد 31536000مرورگر فقط HTTPS بزند
SECURE_HSTS_INCLUDE_SUBDOMAINSTrue (با احتیاط)HSTS برای همه‌ی زیردامنه‌ها
CSRF_TRUSTED_ORIGINS["https://example.ir"]عبور CSRF پشت پراکسی
X_FRAME_OPTIONS"DENY" (پیش‌فرض)جلوگیری از clickjacking

در پایان python manage.py check --deploy را اجرا کنید؛ هر تنظیم جاافتاده را با کد هشدار (مثل security.W004 برای HSTS) گزارش می‌دهد.

نکته‌هایی که کمتر کسی می‌داند

  • با CompressedManifestStaticFilesStorage اگر در قالب به فایلی اشاره کنید که وجود ندارد، با DEBUG=False خطای 500 «Missing staticfiles manifest entry» می‌گیرید؛ قبل از استقرار یک بار محلی با DEBUG=False تست کنید.
  • HSTS را اول با مقدار کوچک روشن کنید؛ اگر یک زیردامنه هنوز HTTPS ندارد و HSTS یک‌ساله با includeSubDomains فرستاده باشید، تا یک سال برای کاربرانی که سایت را دیده‌اند باز نمی‌شود.
  • بدون SECURE_PROXY_SSL_HEADER، SECURE_SSL_REDIRECT=True پشت nginx حلقه‌ی بی‌نهایت ریدایرکت می‌سازد، چون جنگو هر درخواست را HTTP می‌بیند.
  • عبارت alias در nginx حتماً با / تمام شود وقتی location هم با / تمام شده؛ عدم تطابق این دو منشأ خطاهای 404 مرموز media و حتی آسیب‌پذیری path traversal است.
  • Django 5.1 به بعد برای PostgreSQL گزینه‌ی "OPTIONS": {"pool": True} (با psycopg 3 و psycopg-pool) را دارد؛ روی سرورهای پرترافیک جایگزین سبک‌تری برای pgbouncer است.

برای ذخیره‌ی پیشرفت و شرکت در آزمون، وارد شوید — رایگان است.