لایهی جلویی و امنیت نهایی
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
| تنظیم | مقدار | اثر |
|---|---|---|
| DEBUG | False | عدم نمایش جزئیات خطا |
| SECURE_PROXY_SSL_HEADER | ("HTTP_X_FORWARDED_PROTO", "https") | جنگو بفهمد درخواست HTTPS بوده |
| SECURE_SSL_REDIRECT | True | ریدایرکت HTTP به HTTPS |
| SESSION_COOKIE_SECURE / CSRF_COOKIE_SECURE | True | کوکیها فقط روی HTTPS |
| SECURE_HSTS_SECONDS | ابتدا 3600، بعد 31536000 | مرورگر فقط HTTPS بزند |
| SECURE_HSTS_INCLUDE_SUBDOMAINS | True (با احتیاط) | 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 است.