Django Deployment Guide: From Development to Production

Complete Django deployment guide for 2026. Docker, Gunicorn, Nginx, PostgreSQL, SSL, CI/CD. Step-by-step from local development to production server.

DjangoDeploymentDockerDevOpsProduction
Kirill Strelnikov — AI Systems Architect, Barcelona

Why Django Deployment Matters More Than You Think

Building a Django application is only half the job. Deploying it to production — reliably, securely, and with zero downtime — is where many projects stumble. A poorly deployed Django app is slow, insecure, and crashes under load.

This guide covers the production deployment stack I use for every client project: Docker, Gunicorn, Nginx, PostgreSQL, Let's Encrypt SSL, and GitHub Actions CI/CD. Whether you deploy to DigitalOcean, Hetzner, or AWS, the principles are the same.

Production Stack Overview

Step 1: Prepare Django for Production

Before deploying, configure these critical settings:

# settings/production.py
import os

DEBUG = False
ALLOWED_HOSTS = os.environ['ALLOWED_HOSTS'].split(',')
SECRET_KEY = os.environ['SECRET_KEY']

# Security headers
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

# Static files
STATIC_ROOT = '/app/staticfiles'
STORAGES = {
    "staticfiles": {
        "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
    },
}

# Database
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ['DB_NAME'],
        'USER': os.environ['DB_USER'],
        'PASSWORD': os.environ['DB_PASSWORD'],
        'HOST': os.environ['DB_HOST'],
        'PORT': os.environ.get('DB_PORT', '5432'),
    }
}

Security Checklist

Run the Django deployment checklist before going live:

python manage.py check --deploy

This catches common security misconfigurations like DEBUG=True, missing HSTS headers, and insecure cookie settings.

Step 2: Create the Dockerfile

FROM python:3.13-slim

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    libpq-dev gcc && \
    rm -rf /var/lib/apt/lists/*

# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy project
COPY . .

# Collect static files
RUN python manage.py collectstatic --noinput

# Run with Gunicorn
CMD ["gunicorn", "config.wsgi:application", \
     "--bind", "0.0.0.0:8000", \
     "--workers", "3", \
     "--timeout", "120"]

Step 3: Docker Compose for the Full Stack

version: '3.8'

services:
  web:
    build: .
    env_file: .env
    depends_on:
      - db
      - redis
    volumes:
      - static:/app/staticfiles

  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}

  redis:
    image: redis:7-alpine

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
      - static:/app/staticfiles:ro
      - certs:/etc/letsencrypt:ro

volumes:
  pgdata:
  static:
  certs:

Step 4: Configure Nginx

server {
    listen 80;
    server_name yourdomain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    location /static/ {
        alias /app/staticfiles/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    location / {
        proxy_pass http://web:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Step 5: Set Up CI/CD with GitHub Actions

name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run tests
        run: |
          pip install -r requirements.txt
          python manage.py test

      - name: Deploy to server
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /opt/myproject
            git pull origin main
            docker compose build
            docker compose up -d
            docker compose exec web python manage.py migrate

Step 6: Gunicorn Configuration

# gunicorn.conf.py
import multiprocessing

bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "gthread"
threads = 2
timeout = 120
keepalive = 5
max_requests = 1000
max_requests_jitter = 50
accesslog = "-"
errorlog = "-"

The max_requests setting restarts workers after 1,000 requests, preventing memory leaks. worker_class = "gthread" handles concurrent requests better than the default sync worker.

Step 7: Database Backups

Automate daily PostgreSQL backups:

# backup.sh - run via cron daily
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
docker compose exec -T db pg_dump -U $DB_USER $DB_NAME | \
  gzip > /backups/db_${TIMESTAMP}.gz
# Keep last 30 days
find /backups -name "db_*.gz" -mtime +30 -delete

Hosting Costs

For most Django projects with under 50,000 monthly visitors, a EUR 10-15/month VPS is sufficient. I deploy all my client projects using this stack, and it handles production traffic reliably. See my backend development services for deployment assistance.

Need help deploying your Django application? I handle the full stack: Docker, CI/CD, SSL, monitoring, and ongoing maintenance.

Get in touch →

Need an AI automation system built? I architect and build production-grade AI systems for European SMEs. From intelligent chatbots to full backend infrastructure.

Request AI Systems Assessment →

Explore my services:

Resources: