DeployxaDocs Portal
CLI v1.0.4
Deploy Django App (Python 3.11)
Framework guide · Django

Deploy a Django app (Python)

Deploy Django with Gunicorn, collectstatic and WhiteNoise for static files, migrations before each release, managed PostgreSQL and HTTPS.

Prerequisites

  • Django 4.2 LTS or 5.x, with manage.py at the root directory.
  • requirements.txt including gunicorn, whitenoise, dj-database-url and psycopg[binary].

How Deployxa detects Django

manage.py with requirements.txt identifies Django. Choose the Django preset and set the start command below. In these examples the project package is config (so the WSGI module is config.wsgi); replace it with yours.

SettingValue
Build commandpip install -r requirements.txt
Releasepython manage.py migrate --noinput
Start commandgunicorn config.wsgi --bind 0.0.0.0:8000
Static outputstatic (STATIC_ROOT)
Port8000

Required settings

python
# config/settings.py
import os
from pathlib import Path
import dj_database_url

BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = os.environ["SECRET_KEY"]
DEBUG = os.getenv("DEBUG", "0") == "1"
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "").split(",")
CSRF_TRUSTED_ORIGINS = [o for o in os.getenv("CSRF_TRUSTED_ORIGINS", "").split(",") if o]

# HTTPS terminates at the proxy in front of Gunicorn
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
SESSION_COOKIE_SECURE = CSRF_COOKIE_SECURE = not DEBUG

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "whitenoise.middleware.WhiteNoiseMiddleware",   # right after SecurityMiddleware
    # ... the rest of your middleware
]

DATABASES = {
    "default": dj_database_url.config(conn_max_age=600, conn_health_checks=True)
}

STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "static"
STORAGES = {
    "default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
    "staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"},
}

Static files and migrations

Collect static files during the build, and migrate before Gunicorn takes traffic:

shell
# build command
pip install -r requirements.txt && python manage.py collectstatic --noinput

# start command
sh -c 'python manage.py migrate --noinput && gunicorn config.wsgi --bind 0.0.0.0:8000 --workers 3'
Note: If migrate fails, the process exits, the new release never passes its health check, and the previous release keeps serving. Fix the migration and redeploy.

Environment variables

KeyPurposeExample
SECRET_KEYDjango signing keya long random string
ALLOWED_HOSTSComma-separated hostnames, no schememy-app.deployxa.online,example.com
CSRF_TRUSTED_ORIGINSComma-separated origins, with schemehttps://example.com
DATABASE_URLInjected when PostgreSQL is attachedpostgresql://…
DJANGO_SETTINGS_MODULEOnly if you use split settingsconfig.settings.production

Generate a key with python -c "from django.core.management.utils import get_random_secret_key as g; print(g())".

Databases

In the wizard's Configure step, set Database to PostgreSQL. The connection string is injected into the app as DATABASE_URL, so nothing needs to be committed. Choose SQLite only for small apps: it lives on a persistent volume and has no server.

dj_database_url.config() reads DATABASE_URL and accepts both postgres:// and postgresql://. User uploads (MEDIA_ROOT) should go to a persistent volume or S3-compatible storage, because the container filesystem is replaced on every deploy.

Deploy

From the dashboard

  1. 1
    Source

    Open Dashboard → Projects → New project (/dashboard/projects/new). Pick the GitHub repository and branch, or upload a .zip archive of the project.

  2. 2
    Configure

    Leave the framework preset on Auto-detect or choose Django. Check the fields under advanced settings:

    • Build command: pip install -r requirements.txt && python manage.py collectstatic --noinput
    • Output directory: static
    • Root directory: ./, or the sub-folder that holds the app in a monorepo
    • Database: PostgreSQL
  3. 3
    Environment

    Add your variables in the table, or paste a whole .env file into the Bulk / .env tab.

  4. 4
    Deploy

    Start the deploy and watch the build log. When the release passes its health check it is served over HTTPS on its Deployxa URL.

  5. 5
    Confirm the start command and port

    Open the project's Environment Canvas tab and select the web service. Set Start Command to sh -c 'python manage.py migrate --noinput && gunicorn config.wsgi --bind 0.0.0.0:8000'. Set Internal Port to 8000 so it matches the port your app listens on. Save and redeploy if you changed anything.

From the CLI

shell
$ npm install -g @deployxa/cli
$ deployxa login
$ cd my-app
$ deployxa link            # pick an existing project, or skip: deploy creates one
$ deployxa env set ALLOWED_HOSTS "example.com,www.example.com"
$ deployxa deploy
$ deployxa logs --live     # stream build and runtime logs
$ deployxa open            # open the live URL

If the folder is not linked, deployxa deploy creates a project named after the folder and links it (the link is saved in .deployxa/config.json). Later runs deploy the linked project. deployxa status shows the latest deployment and deployxa rollback previous returns to the release before it.

Warning: deployxa deploy packages the folder exactly as it is on disk; it does not read .gitignore. Delete local node_modules, virtualenvs, build output and real .env files first, or deploy from a clean clone. Set secrets with deployxa env set instead of shipping them in the archive.

Prefer a full walkthrough? Follow Tutorial: Django 5 + PostgreSQL REST API.

Custom domain

Go to Dashboard → Domains, choose Connect a domain you already own and pick this project. Deployxa then shows the DNS records to create at your DNS provider:

RecordUse it forValue
AAn apex domain such as example.com85.17.244.184 (DNS only on Cloudflare)
CNAMEA subdomain such as www or appcname.deployxa.com (DNS only on Cloudflare)
TXTOnly when a CDN or proxy (for example Cloudflare orange-cloud) hides the origin recordHost _deployxa-challenge.<your-domain>, value deployxa-verification=…

DNS changes can take several minutes to propagate; use Retry verification once they have. A Let's Encrypt certificate is issued after the domain verifies. From a linked folder you can do the same with the CLI:

shell
$ deployxa domains add app.example.com
$ deployxa dns             # Waiting → Verified → SSL Active
$ deployxa domains list

After the domain verifies, add it to both ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS and redeploy.

Common errors and fixes

SymptomFix
400 Bad Request on every pageThe hostname is missing from ALLOWED_HOSTS. Include the Deployxa URL and every custom domain.
CSRF verification failed on login or formsAdd the full origin (https://example.com) to CSRF_TRUSTED_ORIGINS and set SECURE_PROXY_SSL_HEADER.
Admin has no CSSRun collectstatic in the build and add WhiteNoise middleware.
ValueError: Missing staticfiles manifest entryA template references a file that collectstatic did not find; fix the path or run collectstatic during the build.
django.db.utils.OperationalError: connection refusedNo database attached or DATABASE_URL unset; attach PostgreSQL in the project.
Infinite redirect loop with SECURE_SSL_REDIRECTSet SECURE_PROXY_SSL_HEADER so Django sees the original https request.

Start with deployxa logs --live (or the deployment's log view in the dashboard): the build log shows dependency and compile failures, the runtime log shows crashes and bind errors. See also Troubleshooting.