Django’s default settings are tuned for development. Running them in production leaks debug information, accepts any host, and misses important security headers. This checklist covers the settings that matter, and Django’s own check --deploy command catches most mistakes.
Deployment guide: deploy Django with Gunicorn and Nginx.
1. Run the deployment check
DJANGO_SETTINGS_MODULE=app.settings.production python manage.py check --deploy
It warns about DEBUG, SECRET_KEY, HTTPS, cookies, HSTS and more. Fix everything it reports (or consciously accept it).
2. Configuration from the environment
# settings/production.py
import os
from .base import *
DEBUG = False
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(",")
CSRF_TRUSTED_ORIGINS = ["https://example.com", "https://www.example.com"]
- DEBUG=False in production, always. Debug pages expose settings, SQL and source code.
- SECRET_KEY is long, random, and not in Git. Generate one with
python -c "import secrets; print(secrets.token_urlsafe(50))". - ALLOWED_HOSTS lists only your domains.
Store values in an .env file (chmod 600), or systemd EnvironmentFile=. See twelve-factor app and secrets management.
3. HTTPS and cookies
Behind Nginx terminating TLS:
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000 # start lower (e.g. 3600) and increase
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = "DENY"
Nginx must send X-Forwarded-Proto (proxy_set_header X-Forwarded-Proto $scheme;). Otherwise SECURE_SSL_REDIRECT causes redirect loops. Only trust that header when Django is reachable only through your proxy. See Let’s Encrypt.
4. Database
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ["DB_NAME"],
"USER": os.environ["DB_USER"],
"PASSWORD": os.environ["DB_PASSWORD"],
"HOST": os.environ.get("DB_HOST", "127.0.0.1"),
"CONN_MAX_AGE": 60, # reuse connections
"CONN_HEALTH_CHECKS": True,
}
}
PostgreSQL is the most popular choice for Django. For many workers, add PgBouncer, or Django’s built-in connection pooling (Django 5.1+ with psycopg). See PostgreSQL performance tuning.
5. Caching and sessions
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": os.environ.get("REDIS_URL", "redis://127.0.0.1:6379/1"),
}
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache" # or cached_db
See install Redis.
6. Static and media files
STATIC_ROOT, collectstatic on deploy, and serving via Nginx or WhiteNoise. See Django static files.
7. Logging
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {"console": {"class": "logging.StreamHandler"}},
"root": {"handlers": ["console"], "level": "INFO"},
"loggers": {"django.request": {"handlers": ["console"], "level": "ERROR", "propagate": False}},
}
Log to stdout, and let systemd/journald or Docker collect it. Add an error tracker (Sentry or GlitchTip) for exceptions, with context. See log management and error tracking with Sentry.
8. Email
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = os.environ["EMAIL_HOST"]
EMAIL_PORT = 587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = "[email protected]"
SERVER_EMAIL = "[email protected]"
ADMINS = [("Ops", "[email protected]")]
See transactional email services.
9. Application server and workers
- Gunicorn with
--workers≈ 2×CPU+1 (sync), or Uvicorn workers for async views. See Gunicorn vs Uvicorn. - Background jobs in Celery, not in requests. See Celery workers.
- Migrations run once per deploy (
python manage.py migrate --noinput), not on every worker start.
10. Admin and accounts
- Move the admin off
/admin/(a different URL path), and protect it with 2FA (django-otp), or an IP allowlist. - Use strong password validators (
AUTH_PASSWORD_VALIDATORS). - Keep Django and dependencies updated (
pip list --outdated, Dependabot). Security releases are frequent.
Quick reference
| Setting | Production value |
|---|---|
DEBUG |
False |
SECRET_KEY |
From environment |
ALLOWED_HOSTS |
Your domains |
| HTTPS | SECURE_SSL_REDIRECT, secure cookies, HSTS |
| Proxy | SECURE_PROXY_SSL_HEADER |
| DB | CONN_MAX_AGE, health checks |
| Check | manage.py check --deploy |
Related: deploy FastAPI with Uvicorn and Linux server hardening checklist.