Deploy Django on Temps

Temps detects a Django app from requirements.txt, pyproject.toml, setup.py or Pipfile and uses the python preset: it finds manage.py and <project>/wsgi.py and starts Gunicorn on $PORT with HTTPS. Set STATIC_ROOT and WhiteNoise for static files, link managed PostgreSQL (injected as POSTGRES_URL and POSTGRES_*), and run manage.py migrate yourself after schema changes.

This guide describes how the nightly release channel builds your app, using the Autopack builder. Beta (v0.1.0-beta.56) also builds with Autopack, but some details below may differ. Earlier releases and the stable channel build with Nixpacks and behave differently. To run nightly, see Release channels.

For an overview of self-hosting Django, including costs, see Deploy Django to your own server. Every framework and the preset it needs is listed under Supported platforms.


Quickstart

From your project root, deploy with your preferred package manager:

npx @temps-sdk/cli up --preset python

Temps installs your dependencies and starts your app with Gunicorn. When it finds a manage.py and a <project>/wsgi.py, it runs gunicorn <project>.wsgi:application --bind 0.0.0.0:$PORT, and adds Gunicorn to the build if your dependencies don't include it. The Python version comes from .python-version, runtime.txt or requires-python in pyproject.toml, and defaults to 3.12.

Temps doesn't create a database for you. To use PostgreSQL, add one as described in Managed PostgreSQL.


What Temps handles automatically

FeatureHow Temps handles it
Installuv, Poetry, Pipenv or pip, chosen from your lockfile or manifest (for example pip install -r requirements.txt)
WSGI serverGunicorn with its default settings (one worker); set your own command in a Procfile
Static filesCollected during the build on nightly; needs STATIC_ROOT — see Required Settings
HTTPSLet's Encrypt certificate, auto-renewed
PortPORT env var injected, defaults to 8000
Health checksHTTP check on / at deploy time, or the path set in .temps.yaml

Database migrations are not run automatically — see Run migrations below.


Run migrations

Temps does not have a remote "run one command" CLI action yet, so migrations are run directly against the container over SSH. Find the container name, then run the migration:

bunx @temps-sdk/cli projects show -p my-django-app --json   # note the numeric "id"
bunx @temps-sdk/cli containers list -p <project-id>          # note the container_name
ssh your-server 'docker exec <container_name> python manage.py migrate'

Run this manually (or from your CI/CD pipeline right after the deploy step) every time a deploy includes a schema change.

On the first deploy the tables don't exist yet. If your app's / needs the database, the deploy fails its health check before you can migrate, so point the health check at a view that doesn't, such as a simple /health view, with health.path in .temps.yaml (see Health checks).

Do not add python manage.py migrate to your Dockerfile's CMD or start command — with rolling deploys, restarts, or multiple replicas, the container start command can run more than once, and concurrent migration runs against the same database can conflict or corrupt data.


Required Settings

Ensure your settings.py is production-ready:

# settings.py
import os

# Temps does not inject your domain into the container, so set this yourself
# as a project environment variable, e.g.
#   ALLOWED_HOSTS=app.example.com,www.example.com
# Defaulting to "*" would turn off Django's Host header validation.
ALLOWED_HOSTS = [h.strip() for h in os.environ.get("ALLOWED_HOSTS", "").split(",") if h.strip()]

# Use the managed PostgreSQL database when one is linked; Temps injects
# these variables. Otherwise your existing DATABASES setting stays in place.
if os.environ.get("POSTGRES_HOST"):
    DATABASES = {
        "default": {
            "ENGINE": "django.db.backends.postgresql",
            "NAME": os.environ.get("POSTGRES_DB"),
            "USER": os.environ.get("POSTGRES_USER"),
            "PASSWORD": os.environ.get("POSTGRES_PASSWORD"),
            "HOST": os.environ["POSTGRES_HOST"],
            "PORT": os.environ.get("POSTGRES_PORT", "5432"),
        }
    }

# Serve static files from the app with WhiteNoise (add `whitenoise` to your dependencies)
STATIC_ROOT = BASE_DIR / "staticfiles"
STORAGES = {
    "default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
    "staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"},
}

# Keep your existing middleware and add WhiteNoise right after SecurityMiddleware
MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "whitenoise.middleware.WhiteNoiseMiddleware",
    # ...the rest of your existing middleware, unchanged
]

Nightly builds run python manage.py collectstatic --noinput during the build, so STATIC_ROOT must be set as above. On beta.56 and earlier, collect the files when the container starts by adding a Procfile to your repository root, replacing myproject with your project's package name:

Procfile

web: python manage.py collectstatic --noinput && gunicorn myproject.wsgi:application --bind 0.0.0.0:$PORT

A web: line in a Procfile replaces the start command Temps would otherwise generate. Temps then no longer adds Gunicorn for you, so make sure gunicorn and whitenoise are in your requirements.txt or pyproject.toml; otherwise the container exits with gunicorn: not found.


Environment Variables

npx @temps-sdk/cli environments vars set SECRET_KEY "your-secret-key" -e production

npx @temps-sdk/cli environments vars set DEBUG "False" -e production

npx @temps-sdk/cli environments vars set ALLOWED_HOSTS "yourdomain.com" -e production

When a managed PostgreSQL database is linked, Temps injects POSTGRES_URL, POSTGRES_HOST, POSTGRES_PORT, POSTGRES_DB, POSTGRES_USER and POSTGRES_PASSWORD. It doesn't inject DATABASE_URL.


Managed PostgreSQL

Create a PostgreSQL database under Databases → Create database, then link it from your project's Databases page, or use the services create and services link CLI commands. Temps injects the connection details as the POSTGRES_* variables used in Required Settings. Run migrations yourself as described in Run migrations.


Platform behavior

These rules apply to every app deployed on Temps, regardless of framework.

The one requirement: your app must listen on the port in the PORT environment variable and bind to 0.0.0.0 — not localhost or 127.0.0.1. Temps runs your app in a container and routes traffic from the host, so an app bound to localhost only accepts connections from inside the container and will fail its health check.

Health checks

After your container starts, Temps sends HTTP GET requests to verify it is healthy before routing traffic to it.

  • Path: / (the root of your application) by default
  • Success: 2 consecutive responses with a 2xx, 3xx, 404 or 405 status code
  • Timeout: 300 seconds (5 minutes) for the app to become healthy, fixed in v0.1.0-beta.56. If the app answers with error responses (other 4xx, or 5xx) for 60 seconds in a row, the deployment fails sooner. From the next release the timeout is configurable from 30 to 3600 seconds under Project → Settings → Build & deploy
  • Retry interval: 2 seconds between successful checks, 5 seconds after an error response or a failed connection

Connection errors and other 4xx or 5xx responses are retried until the timeout; if the app hasn't passed by then, the deployment fails. The check runs once, at deploy time. To check a different path, add a .temps.yaml to your repository root:

.temps.yaml
health:
  path: /health

Only path is used. Other health fields (status, interval, timeout, retries) are accepted but currently have no effect.

Add a dedicated /health endpoint that returns a simple 200. This avoids issues where / requires authentication or returns a redirect.

Auto-injected environment variables

Temps injects these variables into every deployment automatically:

VariableValueDescription
PORTResolved portThe port your app must listen on
HOST0.0.0.0Bind address
SENTRY_DSNAuto-generatedError tracking endpoint
TEMPS_API_URLYour Temps URLPlatform API endpoint
TEMPS_API_TOKENDeployment tokenAuthentication for Temps SDKs
OTEL_EXPORTER_OTLP_ENDPOINTYour Temps OTLP URLOpenTelemetry trace collection
OTEL_SERVICE_NAMEProject nameService identifier for traces

You do not need to configure these manually. They are available in process.env (Node.js), os.environ (Python), os.Getenv (Go), and the equivalent in other languages.


Next Steps

Last updated

Was this page helpful?