Out Plane
Frameworks

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.txt

Static 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:

VariableNotes
SECRET_KEYRead from the environment, never hardcoded.
DEBUGDefault to False in production.
ALLOWED_HOSTSInclude your app's URL, such as {name}-{port}-{team}.outplane.app, and any custom domain.
CSRF_TRUSTED_ORIGINSThe full https:// origin of each host.
DATABASE_URLThe connection string from your database.

Production Notes

  • With DEBUG=False, a missing or wrong ALLOWED_HOSTS returns 400 for every request.
  • Django 4 and later reject form posts unless CSRF_TRUSTED_ORIGINS includes the full https:// origin.
  • SQLite does not survive in a container. Use the managed database.

Next Steps

On this page