Skip to main content
This guide walks you through deploying a Django application on Upsun step by step — from a blank project to a live URL. If you have read the Getting started guide, this page adds Django-specific detail that the generic guide skips. If you haven’t, no problem — this guide is self-contained. You also need Python 3.9+ and pip installed locally.

1. Create a Django project

Create a directory, activate a virtual environment, and install Django:

Windows

Replace source venv/bin/activate with venv\Scripts\activate.
Scaffold the project. The trailing . places all files directly in the current directory and avoids a nested folder:
Your directory now looks like this:
Initialize a Git repository and make your first commit:

2. Add production dependencies

Upsun runs your Django app using Gunicorn, a production-grade WSGI server. You also need a database adapter that matches your chosen database.
Save the dependency list so Upsun can install it at build time:

3. Set environment variables

Create a .environment file at the root of your project. Upsun sources this file automatically before starting your app, on every environment (production, preview branches, etc.).
.environment
What each variable does:
  • DJANGO_SETTINGS_MODULE — tells Django which settings file to load.
  • DJANGO_SECRET_KEY — uses PLATFORM_PROJECT_ENTROPY, a unique value Upsun generates per project. The key is never stored in your repository.
  • DJANGO_ALLOWED_HOSTS — dynamically extracts the hostname of the current environment from your project routes, so every preview branch and production environment works automatically.

Commit .environment to Git

This file contains no secrets — the values are resolved at runtime from Upsun variables. It must be committed so Upsun can source it on every deploy.

4. Update settings.py

Open mysite/settings.py and make three changes. Add import os at the top of the file, after from pathlib import Path:
mysite/settings.py
Replace the ALLOWED_HOSTS line. The default [] rejects all requests when DEBUG = False. Use the environment variable set in the previous step:
mysite/settings.py
Add the Upsun production block at the very bottom of the file. It only activates when PLATFORM_APPLICATION_NAME is present — a variable Upsun injects automatically at runtime. Your local development settings are untouched.
mysite/settings.py
The DATABASE_* environment variables are exposed automatically by the relationship you define in the next step.

5. Create your Upsun project

If you don’t have an Upsun project yet, create one with the CLI:
The CLI asks for a project name and region, then automatically links your local repository to the new project.

Already have a project?

If you created a project from the Upsun Console, link your local repository to it:
Find your project ID in the console or by running upsun project:list.

6. Configure Upsun

Create a .upsun/ directory at the root of your project, then add a config.yaml file inside it. This single file defines your application container, database service, and routing. Key points:
  • build: flavor: none — disables default build behaviors so only your hooks.build commands run.
  • relationships — exposes DATABASE_* environment variables to your app (used by settings.py).
  • hooks.build — installs Python dependencies during the build phase (no database access yet).
  • hooks.deploy — runs collectstatic and migrations at deploy time (database is available).
  • mounts — declares static/ as a persistent writable directory for collected static files.
  • web.commands.start — starts Gunicorn over a Unix socket ($SOCKET), which Upsun manages automatically.

7. Deploy

Push everything to Upsun:
The first deploy installs dependencies, collects static files, and runs database migrations. It takes a minute or two. Subsequent deploys are faster. Open your app once the deploy completes:

Troubleshooting

400 Bad Request on every page ALLOWED_HOSTS is rejecting the request. Check two things:
  1. mysite/settings.py has ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', 'localhost').split(',') at the top level — not inside the if block.
  2. .environment is committed to Git.
Build fails — mysqlclient or psycopg2 not found requirements.txt is missing the database adapter. Run:
gunicorn: command not found in deploy logs Same cause — gunicorn is missing from requirements.txt. Apply the same fix above. Static files return 404 Check that STATIC_ROOT in settings.py uses os.path.join(os.getenv('PLATFORM_APP_DIR'), 'static') and that the mount key in .upsun/config.yaml is also static. They must match exactly.

Further resources

Documentation

Blogs

Last modified on June 23, 2026