Deploy Django to Production with Temps
Deploy Django with Temps: git-push deploys, automatic HTTPS via Pingora, managed PostgreSQL auto-provisioned on first deploy, automatic migrations, and built-in monitoring.
Temps Team
June 6, 2026 · 2mo ago
Deploying Django to production without a dedicated DevOps team means wrestling with Nginx, Gunicorn process management, SSL certificates, static file serving, and database migrations — all before your first user ever hits the site. Temps collapses that entire stack into a single Rust binary you control: git-push to deploy, automatic HTTPS via Pingora (Cloudflare's open-source proxy), managed PostgreSQL auto-provisioned on first deploy, migrations that run automatically, and built-in error tracking, analytics, and uptime monitoring — free to self-host, or on the upcoming Temps Cloud managed add-on.
TL;DR:
bunx @temps-sdk/cli deploy my-django-app -b main -e production -y— your Django app is live with HTTPS, managed PostgreSQL, automatic migrations, and health-checked rollbacks in under 2 minutes. Temps is Apache 2.0, self-hostable for free, with an optional Temps Cloud managed add-on (telemetry retention, offsite backups, AI credits) coming soon.
How Do I Deploy Django to Production Without a Managed Platform?
The fastest path: push your code to a git repository, connect it to Temps, and run one CLI command. Temps detects your Python project via Nixpacks, generates an optimized Dockerfile, installs your dependencies, runs python manage.py migrate before traffic switches over, and starts routing encrypted traffic — all without you touching Nginx, Gunicorn config, or SSL tooling.
What You'll Get
After this tutorial, your Django app will have:
- Gunicorn WSGI server — the production-grade server Django recommends, configured automatically
- Managed PostgreSQL provisioned automatically — database is ready before your first deploy completes
- Automatic database migrations —
python manage.py migrateruns on every deploy before traffic switches - Static files via WhiteNoise — no separate CDN or Nginx config required for serving static assets
- Auto-rollback — health checks every 5 seconds, 2 consecutive failures trigger rollback within 60 seconds
- Automatic HTTPS via Let's Encrypt, renewed without intervention
- Built-in error tracking and request analytics — no Sentry subscription needed
- Encrypted environment variables —
SECRET_KEY,DATABASE_URL, and other secrets injected at runtime, never baked into images
Prerequisites
- A Django application (3.2 or newer)
- Git repository (GitHub, GitLab, or Bitbucket)
- Python 3.9+ project with
requirements.txt,pyproject.toml, orPipfile
How Do I Deploy Django to Production Without Heroku?
Heroku's free tier is gone, and paying for dynos gets expensive fast — especially when you need managed Postgres, SSL, and process management. Temps gives you the same git-push workflow on infrastructure you control, with no per-seat fees and no bandwidth bills.
Comparing Django Deployment Options
| Feature | Temps | PythonAnywhere | Render | Railway |
|---|---|---|---|---|
| Git-push deploys | Yes | Partial (manual) | Yes | Yes |
| Managed PostgreSQL | Included | See their pricing page | See their pricing page | See their pricing page |
| Automatic HTTPS | Yes (Let's Encrypt) | Yes | Yes | Yes |
| Static files | WhiteNoise (built-in) | Manual config required | Manual config required | Manual config required |
| Error tracking | Built-in (no extra cost) | No | No | No |
| Session replay | Built-in (no extra cost) | No | No | No |
| Request analytics | Built-in (no extra cost) | No | No | No |
| Self-host option | Yes (Apache 2.0) | No | No | No |
| Auto-rollback | Yes (60s window) | No | Health checks | Health checks |
| Pricing | Free self-host | See their pricing page | See their pricing page | See their pricing page |
| Vendor lock-in | None — runs on any Linux server | Proprietary | Proprietary | Proprietary |
Project Structure
Temps works with any Django project layout. Here's a minimal production-ready example:
my-django-app/
├── manage.py
├── myproject/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── requirements.txt # or pyproject.toml / Pipfile
└── .env # optional, local development only
requirements.txt (production-ready):
Django>=4.2
gunicorn>=21.2.0
psycopg2-binary>=2.9
whitenoise>=6.6.0
dj-database-url>=2.1.0
Deploy Django with the Temps CLI
Step 1: Install Temps CLI
# macOS / Linux
curl -fsSL https://temps.sh/install.sh | bash
Step 2: Login and Create Project
bunx @temps-sdk/cli login
# Create project and connect your git repository
bunx @temps-sdk/cli projects create \
-n "My Django App" \
-d "Django application" \
--repo your-org/your-django-app \
--branch main \
--preset python
Temps automatically detects Python projects via Nixpacks. Use --preset docker if you already have a Dockerfile.
Step 3: Configure Environment Variables
Django requires several production environment variables. Set them before deploying:
# Django secret key (generate a strong random value)
bunx @temps-sdk/cli environments vars set SECRET_KEY "your-secret-key-here" -e production
# Database URL (Temps provisions this automatically — copy the value from your dashboard)
bunx @temps-sdk/cli environments vars set DATABASE_URL "postgresql://user:pass@host:5432/db" -e production
# Allowed hosts (your domain or Temps subdomain)
bunx @temps-sdk/cli environments vars set ALLOWED_HOSTS "my-django-app.temps.sh,yourdomain.com" -e production
# Disable debug mode in production
bunx @temps-sdk/cli environments vars set DEBUG "False" -e production
# Or import all at once from a file
bunx @temps-sdk/cli environments vars import .env.production -e production
Step 4: Configure settings.py for Production
Update your Django settings to read from environment variables:
import os
import dj_database_url
SECRET_KEY = os.environ.get("SECRET_KEY")
DEBUG = os.environ.get("DEBUG", "False") == "True"
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "").split(",")
# Database — auto-configured from DATABASE_URL env var
DATABASES = {
"default": dj_database_url.config(
default=os.environ.get("DATABASE_URL"),
conn_max_age=600,
conn_health_checks=True,
)
}
# Static files — WhiteNoise serves them without a separate CDN
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware", # immediately after SecurityMiddleware
# ... rest of your middleware
]
STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
# WhiteNoise compression and caching
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
Step 5: Deploy
bunx @temps-sdk/cli deploy my-django-app -b main -e production -y
Temps will:
- Detect your Django application via Nixpacks
- Generate an optimized Dockerfile (unless you supply one)
- Install dependencies (
pip install -r requirements.txt) - Run
python manage.py collectstatic --noinput - Run
python manage.py migratebefore traffic switches over - Deploy to production with Gunicorn as the WSGI server
- Provision an SSL certificate via Let's Encrypt
Your app is live at your-app.temps.sh within ~2 minutes.
Managed PostgreSQL
Temps provisions a managed PostgreSQL database automatically when you first deploy. You don't need to create or configure it manually.
The DATABASE_URL environment variable is injected into your container at runtime. Your dj_database_url.config() call picks it up automatically — no hardcoded credentials, no connection string in your image layers.
What's included:
- PostgreSQL with automatic backups
- Connection pooling ready
- HA (high-availability) cluster available for production workloads
- Database migrations run automatically on every deploy
Static Files with WhiteNoise
Django's built-in runserver serves static files in development, but it's not designed for production. WhiteNoise handles this cleanly without a separate Nginx or CDN configuration:
- Add
whitenoisetorequirements.txt - Add
whitenoise.middleware.WhiteNoiseMiddlewaretoMIDDLEWARE(afterSecurityMiddleware) - Set
STATIC_ROOTand useCompressedManifestStaticFilesStorage
Temps runs python manage.py collectstatic --noinput automatically during the build phase. Your static files are served with correct cache headers and gzip compression from day one.
Health Check Endpoint
Temps polls your health endpoint every 5 seconds. Two consecutive failures within the 60-second error window trigger automatic rollback to the last healthy deployment. Add a lightweight /health view:
# urls.py
from django.urls import path
from django.http import JsonResponse
def health_check(request):
return JsonResponse({"status": "healthy"})
urlpatterns = [
path("health/", health_check),
# ... your other URLs
]
Keep it fast and dependency-free. Optionally check database connectivity:
from django.db import connections
from django.db.utils import OperationalError
def health_check(request):
try:
connections["default"].cursor()
except OperationalError:
return JsonResponse({"status": "error", "db": "unreachable"}, status=503)
return JsonResponse({"status": "healthy"})
Automatic Dockerfile Generation
You don't need Docker knowledge. Temps generates an optimized Dockerfile for your Django project:
Generated Dockerfile:
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# Collect static files
RUN python manage.py collectstatic --noinput
# Run with Gunicorn (production WSGI server)
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]
If you have a custom Dockerfile, Temps uses that instead.
Environment Variables
Managing Variables
# Single variable
bunx @temps-sdk/cli environments vars set SECRET_KEY "$(python -c 'import secrets; print(secrets.token_urlsafe(50)')" -e production
# List all (values hidden by default)
bunx @temps-sdk/cli environments vars list -e production
# Import from file
bunx @temps-sdk/cli environments vars import .env.production -e production
Key Variables for Django Production
| Variable | Purpose | Example |
|---|---|---|
SECRET_KEY | Django cryptographic signing | A 50+ character random string |
DATABASE_URL | PostgreSQL connection string | Auto-injected by Temps |
ALLOWED_HOSTS | Request host validation | myapp.temps.sh,myapp.com |
DEBUG | Disable debug mode | False |
DJANGO_SETTINGS_MODULE | Settings file to use | myproject.settings.production |
Environment variables are encrypted at rest and injected at runtime — they never appear in your Docker image layers.
Built-in Monitoring
After deployment, your Temps dashboard includes monitoring at no extra cost:
Request Analytics
- Request count and latency percentiles (p50, p95, p99)
- Endpoint breakdown with per-route timing
- Error rates by view
- Geographic distribution of traffic
Error Tracking
- Exception capture with full Django stack traces
- Request context (headers, user, environment)
- Error grouping and trend analysis
No Sentry, no Datadog, no Rollbar. It's built into the same binary that runs your proxy. Temps also exposes a Sentry-compatible DSN if you want to use the Sentry SDK client-side alongside the built-in server-side tracking.
Uptime Monitoring
Temps checks your health endpoint continuously and alerts you to outages — replacing tools like Pingdom or Better Uptime for basic production monitoring.
Custom Domains
DNS Configuration
Add an A record pointing to your Temps server IP:
| Type | Name | Value |
|---|---|---|
| A | @ | YOUR_SERVER_IP |
| A | www | YOUR_SERVER_IP |
Adding Your Domain
# HTTP-01 challenge (default, works for most domains)
bunx @temps-sdk/cli domains add -d yourdomain.com
# DNS-01 challenge (required for wildcard domains)
bunx @temps-sdk/cli domains add -d "*.yourdomain.com" --challenge dns-01
Update ALLOWED_HOSTS in your environment variables to include your custom domain:
bunx @temps-sdk/cli environments vars set ALLOWED_HOSTS "yourdomain.com,www.yourdomain.com" -e production
Scaling Your Application
Horizontal Scaling
Scale to multiple replicas:
bunx @temps-sdk/cli environments scale -e production -r 3
Temps handles load balancing automatically via Pingora, Cloudflare's open-source Rust proxy.
Update Resource Allocation
bunx @temps-sdk/cli projects config -p my-django-app \
--cpu-limit 2 \
--memory-limit 1024 \
-y
bunx @temps-sdk/cli deploy my-django-app -b main -e production -y
Troubleshooting
Build Fails
Check build logs in the Temps dashboard or stream them via CLI:
bunx @temps-sdk/cli deploy my-django-app -b main -e production
Common issues:
- Missing packages in
requirements.txt(e.g.,psycopg2-binary,gunicorn,whitenoise) - Python version mismatch — specify
FROM python:3.11-slimin a custom Dockerfile collectstaticfailing becauseSECRET_KEYisn't available at build time — set a dummy build-time value or defer static collection to startup
App Crashes on Start
# Stream live logs
bunx @temps-sdk/cli runtime-logs -p my-django-app -f
- Check that
SECRET_KEY,DATABASE_URL, andALLOWED_HOSTSare all set - Confirm
DEBUG=Falseis set — Django will refuse to start with a missingSECRET_KEYwhenDEBUG=False - Confirm the Gunicorn command points to the correct WSGI module (
myproject.wsgi:application) - Confirm the app binds to
0.0.0.0:8000(not127.0.0.1)
Migrations Fail
Temps runs python manage.py migrate automatically. If migrations fail:
# Check migration status
bunx @temps-sdk/cli runtime-logs -p my-django-app -f
- Verify
DATABASE_URLis set correctly in theproductionenvironment - Check for unapplied squashed migrations or dependency conflicts
- Use
--run-syncdbonly for apps without migrations (not recommended for production)
Health Check Failures
Temps checks your health endpoint every 5 seconds. Keep it fast:
def health_check(request):
return JsonResponse({"status": "ok"}) # No DB query — fast and dependency-free
FAQ
Do I need Gunicorn?
Yes — Django's built-in runserver is not safe for production. Temps uses Gunicorn as the production WSGI server automatically. Nixpacks detects Django and configures Gunicorn for you; if you supply your own Dockerfile, include gunicorn in your requirements.txt and set it as the CMD.
How do I run manage.py migrate?
You don't need to. Temps runs python manage.py migrate automatically on every deploy, before traffic switches to the new container. This means your database schema is always in sync with your deployed code. If a migration fails, the deploy stops and the previous version keeps serving traffic.
Does Temps support Django Channels?
Django Channels (WebSockets and async consumers) requires an ASGI server such as Daphne or Uvicorn instead of Gunicorn. Temps supports ASGI applications — supply a custom Dockerfile that runs daphne or uvicorn myproject.asgi:application as the CMD, and Temps will deploy it the same way. The Pingora proxy handles WebSocket upgrades correctly.
Is this free?
Temps is Apache 2.0, so self-hosting is completely free — you only pay for the server you run it on. If you'd rather not operate infrastructure yourself, Temps Cloud is a managed add-on (telemetry retention, offsite backups, AI credits) coming soon; pricing hasn't been announced yet.
Can I use a different database?
Yes. While Temps auto-provisions PostgreSQL, you can connect to any external database by setting the appropriate environment variable. MySQL, SQLite (not recommended for production), and any other Django-compatible backend are supported as long as you include the driver in requirements.txt.
What Python version does Temps use?
Nixpacks reads your .python-version file, runtime.txt, or pyproject.toml to select the Python version. If none is specified, it defaults to a recent stable Python 3 release. To pin a version, add a .python-version file:
3.11
Quick Reference
# Install CLI
curl -fsSL https://temps.sh/install.sh | bash
# Login
bunx @temps-sdk/cli login
# Create project and connect repo
bunx @temps-sdk/cli projects create \
-n "My Django App" \
-d "Django application" \
--repo myorg/my-django-app \
--branch main \
--preset python
# Set required environment variables
bunx @temps-sdk/cli environments vars set SECRET_KEY "your-secret-key" -e production
bunx @temps-sdk/cli environments vars set ALLOWED_HOSTS "my-django-app.temps.sh" -e production
bunx @temps-sdk/cli environments vars set DEBUG "False" -e production
# Deploy (migrations run automatically)
bunx @temps-sdk/cli deploy my-django-app -b main -e production -y
# Stream live logs
bunx @temps-sdk/cli runtime-logs -p my-django-app -f
# Scale replicas
bunx @temps-sdk/cli environments scale -e production -r 3
# Add custom domain
bunx @temps-sdk/cli domains add -d yourdomain.com
Ready to deploy your Django app? Get started at temps.sh — self-host for free (Apache 2.0), with a managed Temps Cloud add-on coming soon:
curl -fsSL https://temps.sh/install.sh | bash && bunx @temps-sdk/cli login
Get weekly updates