Deploy Django
Deploy a Django application on Out Plane, with Gunicorn, static files, a database, and migrations.
This guide deploys a Django project with Gunicorn, serves static files with WhiteNoise, and connects to a managed PostgreSQL database. For the shared deploy flow, see Deploy from GitHub.
Prepare Your App
Production Server
Serve with Gunicorn, not runserver. Gunicorn binds 127.0.0.1 by default, so you must
bind 0.0.0.0 and the port you expose. Because the start command runs as a direct exec,
wrap it in sh -c so $PORT expands:
sh -c "gunicorn myproject.wsgi:application --bind 0.0.0.0:$PORT --workers 4"Replace myproject with the package that holds wsgi.py. Add gunicorn, whitenoise,
and a PostgreSQL driver to your requirements:
pip install gunicorn whitenoise "psycopg[binary]" dj-database-url
pip freeze > requirements.txtStatic Files
Django does not serve static files in production, so use WhiteNoise. Add its middleware
right after SecurityMiddleware, and set a static root:
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
# ...
]
STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "staticfiles"
STORAGES = {
"staticfiles": {
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
},
}Run python manage.py collectstatic --no-input during the build.
Deploy
Create an application from your repository. Buildpacks installs your requirements, or
use a Dockerfile. Set the Gunicorn start command above, and expose the port.
Connect a Database
Create a managed PostgreSQL database and copy its connection
string into a DATABASE_URL environment variable.
Read it with dj-database-url, and require SSL:
import os, dj_database_url
DATABASES = {
"default": dj_database_url.config(
default=os.environ["DATABASE_URL"],
conn_max_age=600,
ssl_require=True,
),
}Run Migrations
Out Plane has no pre deploy hook. Run migrations at boot before Gunicorn starts, or once from the browser terminal:
sh -c "python manage.py migrate --no-input && gunicorn myproject.wsgi:application --bind 0.0.0.0:$PORT"The browser terminal is also where you run python manage.py createsuperuser.
Environment Variables
Set these as environment variables:
| Variable | Notes |
|---|---|
SECRET_KEY | Read from the environment, never hardcoded. |
DEBUG | Default to False in production. |
ALLOWED_HOSTS | Include your app's URL, such as {name}-{port}-{team}.outplane.app, and any custom domain. |
CSRF_TRUSTED_ORIGINS | The full https:// origin of each host. |
DATABASE_URL | The connection string from your database. |
Production Notes
- With
DEBUG=False, a missing or wrongALLOWED_HOSTSreturns400for every request. - Django 4 and later reject form posts unless
CSRF_TRUSTED_ORIGINSincludes the fullhttps://origin. - SQLite does not survive in a container. Use the managed database.