How to Deploy a Django App to Production (2026 Guide)
Deploy Django with Gunicorn, PostgreSQL, WhiteNoise static files and automatic migrations: production settings, ALLOWED_HOSTS, CSRF and a one-command deploy.
- Published
- Reading time
- 4 min
On this page
Key takeaways
- Production Django needs four settings from the environment: SECRET_KEY, DEBUG=False, ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS.
- Read the database from DATABASE_URL with dj-database-url, and serve static files with WhiteNoise.
- On DockHosting, Gunicorn is configured for you and manage.py migrate runs automatically before traffic switches.
To deploy a Django app to production you need five things: settings read from the environment (SECRET_KEY, DEBUG=False, ALLOWED_HOSTS, CSRF_TRUSTED_ORIGINS), a WSGI server (Gunicorn), a production database read from DATABASE_URL with dj-database-url, static files served by WhiteNoise after collectstatic, and migrations that run before traffic switches. On DockHosting, Gunicorn and manage.py migrate are handled automatically, so the deploy itself is one command: dock deploy.
1. Production settings from the environment
Hard-coded secrets and DEBUG = True are the two classic Django deploy mistakes. Read both from the environment:
# settings.py
import os
import dj_database_url
SECRET_KEY = os.environ["SECRET_KEY"]
DEBUG = os.environ.get("DEBUG", "False") == "True"
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "").split(",")
CSRF_TRUSTED_ORIGINS = [f"https://{h}" for h in ALLOWED_HOSTS if h]
DATABASES = {"default": dj_database_url.config(conn_max_age=600)}Generate a strong key once and store it as a secret:
python -c "import secrets; print(secrets.token_urlsafe(50))"2. Static files with WhiteNoise
With DEBUG=False, Django stops serving CSS and JavaScript (including the admin's). WhiteNoise serves them efficiently from your app:
# settings.py
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware", # right after SecurityMiddleware
# …
]
STATIC_ROOT = BASE_DIR / "staticfiles"
STORAGES = {
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
"staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"},
}Files have to be collected at build time. Add collectstatic to your project's build command in the dashboard:
python manage.py collectstatic --noinput3. Dependencies
# requirements.txt
django
gunicorn
dj-database-url
psycopg[binary]
whitenoisePin versions (pip freeze > requirements.txt) so production installs exactly what you tested. Poetry users can keep pyproject.toml: it's detected too.
4. Deploy
curl -fsSL https://cli.dockhosting.dev/install.sh | sh # Windows: irm https://cli.dockhosting.dev/install.ps1 | iex
dock login
dock deployWhat happens:
manage.pymarks the project as Django, on Python 3.11 or 3.12.- Dependencies are installed with pip or Poetry.
- Gunicorn workers are configured for you, so you don't need a Procfile.
python manage.py migrateruns automatically before traffic switches to the new release, so your schema is never behind your code.- You get
https://<project>.dockhosting.cloudwith automatic HTTPS.
Set SECRET_KEY and ALLOWED_HOSTS (for example myapp.dockhosting.cloud) in the project's environment variables.
5. Add PostgreSQL
Create a managed PostgreSQL database in the dashboard and attach it to the project. DATABASE_URL is injected over a private network, and the dj_database_url.config() line above picks it up with no code changes. Create your admin user from your machine through public database access (Hobby and up), or with a data migration.
Need Redis for caching or Celery? Attach managed Redis and read REDIS_URL.
6. Production checklist
| Setting | Value |
|---|---|
DEBUG | False |
SECRET_KEY | From the environment, 50+ random characters |
ALLOWED_HOSTS | Your .dockhosting.cloud host and custom domains |
CSRF_TRUSTED_ORIGINS | The same hosts, with https:// |
SECURE_PROXY_SSL_HEADER | ("HTTP_X_FORWARDED_PROTO", "https") if you use SECURE_SSL_REDIRECT |
| Static files | WhiteNoise + collectstatic in the build |
Run python manage.py check --deploy locally. It flags most of these for you.
Troubleshooting
DisallowedHost: add the host toALLOWED_HOSTS.- CSRF failed on login or forms: add the
https://origin toCSRF_TRUSTED_ORIGINS. - 502 after deploy: see 8 causes of a 502 and how to fix them.
Prefer async APIs? See deploying FastAPI.
Frequently asked questions
Do I need a Procfile or Dockerfile to deploy Django?
No. DockHosting detects Django from manage.py, installs dependencies with pip (requirements.txt) or Poetry (pyproject.toml), runs Gunicorn workers and runs migrate before the new release takes traffic.
Which Python versions are supported?
Python 3.11 and 3.12.
Why do I get 'CSRF verification failed' in production?
Since Django 4.0, CSRF checks the Origin header against CSRF_TRUSTED_ORIGINS, which must include the scheme, for example https://myapp.dockhosting.cloud. Add every domain your site is served from.
Why are my static files (CSS, admin styles) missing?
With DEBUG=False, Django no longer serves static files. Add WhiteNoise middleware and make sure collectstatic runs during the build.
- Django
- Python
- PostgreSQL
- Deployment
- Tutorial
Written by Doughmi ILYAS
Doughmi builds DockHosting, the developer-first platform behind dock deploy: the build system, the managed databases and the dashboard. On this blog: guides to shipping apps without running servers, written with the commands the platform actually ships.
