pip installed locally.
1. Create a Django project
Create a directory, activate a virtual environment, and install Django:Windows
Replacesource venv/bin/activate with venv\Scripts\activate.. places all files directly in the current directory and avoids a nested folder:
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.- MariaDB
- PostgreSQL
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
DJANGO_SETTINGS_MODULE— tells Django which settings file to load.DJANGO_SECRET_KEY— usesPLATFORM_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.
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
ALLOWED_HOSTS line. The default [] rejects all requests when DEBUG = False.
Use the environment variable set in the previous step:
mysite/settings.py
PLATFORM_APPLICATION_NAME is present — a variable Upsun injects automatically at runtime.
Your local development settings are untouched.
- MariaDB
- PostgreSQL
mysite/settings.py
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:Already have a project?
If you created a project from the Upsun Console, link your local repository to it: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 yourhooks.buildcommands run.relationships— exposesDATABASE_*environment variables to your app (used bysettings.py).hooks.build— installs Python dependencies during the build phase (no database access yet).hooks.deploy— runscollectstaticand migrations at deploy time (database is available).mounts— declaresstatic/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:Troubleshooting
400 Bad Request on every pageALLOWED_HOSTS is rejecting the request. Check two things:
mysite/settings.pyhasALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', 'localhost').split(',')at the top level — not inside theifblock..environmentis committed to Git.
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.