Deployment | Django LiveView

Deploying Django LiveView requires an ASGI server (like Daphne or Uvicorn), Redis for the channel layer, and proper WebSocket support.

Production Requirements

  • ASGI Server: Daphne, Uvicorn, or Hypercorn

  • Redis: For channel layer (shared state between workers)

  • WebSocket Support: Reverse proxy must support WebSockets (Nginx, Caddy, Traefik)

  • Process Manager: Supervisor, systemd, or Docker

  • SSL/TLS: Required for wss:// connections in production

Using Daphne (Recommended)

Install Daphne:

pip install daphne

Run Daphne in production:

daphne -b 0.0.0.0 -p 8000 myproject.asgi:application

With multiple workers for better performance:

daphne -b 0.0.0.0 -p 8000 --workers 4 myproject.asgi:application

Using Uvicorn

Install Uvicorn:

pip install uvicorn[standard]

Run Uvicorn:

uvicorn myproject.asgi:application --host 0.0.0.0 --port 8000 --workers 4

Redis Configuration for Production

Update settings.py for production Redis:

# settings.py
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": [
                {
                    "address": ("redis", 6379),  # Redis hostname
                    "password": "your-redis-password",
                    "db": 0,
                }
            ],
            "capacity": 1500,  # Max messages per channel
            "expiry": 10,      # Message expiry in seconds
        },
    },
}

For Redis Sentinel (high availability):

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": [
                {
                    "sentinels": [
                        ("sentinel1", 26379),
                        ("sentinel2", 26379),
                        ("sentinel3", 26379),
                    ],
                    "master_name": "mymaster",
                    "password": "your-redis-password",
                }
            ],
        },
    },
}

Nginx Configuration

Configure Nginx to proxy WebSocket connections:

upstream django {
    server 127.0.0.1:8000;
}

server {
    listen 80;
    server_name example.com;

    # Redirect HTTP to HTTPS
    return 301 https://$server_name$request_uri;
}

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

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # Static files
    location /static/ {
        alias /path/to/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    location /media/ {
        alias /path/to/media/;
        expires 7d;
    }

    # WebSocket support
    location /ws/ {
        proxy_pass http://django;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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;

        # Increase timeout for long-lived connections
        proxy_read_timeout 86400;
        proxy_send_timeout 86400;
    }

    # Regular HTTP requests
    location / {
        proxy_pass http://django;
        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;
    }
}

Docker Deployment

Dockerfile:

FROM python:3.11-slim

WORKDIR /app

# Install 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

# Expose port
EXPOSE 8000

# Run Daphne
CMD ["daphne", "-b", "0.0.0.0", "-p", "8000", "myproject.asgi:application"]

docker-compose.yml:

version: '3.8'

services:
  redis:
    image: redis:7-alpine
    restart: always
    volumes:
      - redis_data:/data
    command: redis-server --requirepass your-redis-password

  web:
    build: .
    restart: always
    ports:
      - "8000:8000"
    depends_on:
      - redis
    environment:
      - REDIS_HOST=redis
      - REDIS_PASSWORD=your-redis-password
      - DJANGO_SETTINGS_MODULE=myproject.settings
    volumes:
      - static_volume:/app/staticfiles
      - media_volume:/app/media

  nginx:
    image: nginx:alpine
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - static_volume:/static:ro
      - media_volume:/media:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - web

volumes:
  redis_data:
  static_volume:
  media_volume:

Systemd Service

Create /etc/systemd/system/django-liveview.service:

[Unit]
Description=Django LiveView Application
After=network.target redis.service

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/path/to/project
Environment="PATH=/path/to/venv/bin"
ExecStart=/path/to/venv/bin/daphne -b 0.0.0.0 -p 8000 myproject.asgi:application
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl enable django-liveview
sudo systemctl start django-liveview
sudo systemctl status django-liveview

Environment Variables

Store sensitive configuration in environment variables:

# settings.py
import os

SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY")
DEBUG = os.environ.get("DJANGO_DEBUG", "False") == "True"

ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(",")

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": [{
                "address": (
                    os.environ.get("REDIS_HOST", "127.0.0.1"),
                    int(os.environ.get("REDIS_PORT", 6379))
                ),
                "password": os.environ.get("REDIS_PASSWORD"),
            }],
        },
    },
}

Performance Tuning

  1. Use Redis persistence (appendonly yes) for channel layer reliability

  2. Increase worker count based on CPU cores (workers = CPU cores * 2 + 1)

  3. Set proper capacity and expiry in channel layer config

  4. Enable HTTP/2 in Nginx for better performance

  5. Use connection pooling for database

  6. Configure WebSocket timeouts appropriately

  7. Monitor Redis memory usage and set maxmemory limits

Monitoring

Monitor your Django LiveView application:

# settings.py
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "handlers": {
        "file": {
            "level": "INFO",
            "class": "logging.FileHandler",
            "filename": "/var/log/django/liveview.log",
        },
    },
    "loggers": {
        "liveview": {
            "handlers": ["file"],
            "level": "INFO",
            "propagate": False,
        },
    },
}

Monitor key metrics:

  • WebSocket connection count

  • Redis memory usage

  • Handler execution time

  • Error rates

  • Message throughput

Security Checklist

  • ✓ Use HTTPS/WSS in production

  • ✓ Set ALLOWED_HOSTS correctly

  • ✓ Use AllowedHostsOriginValidator in ASGI

  • ✓ Enable Redis password authentication

  • ✓ Set proper CORS headers if needed

  • ✓ Use authentication middleware for protected handlers

  • ✓ Validate and sanitize all user input

  • ✓ Set WebSocket rate limiting

  • ✓ Monitor for suspicious activity

Scaling Horizontally

To scale beyond one server:

  1. Use external Redis (not Redis on the same server)

  2. Share sessions across servers (database or Redis sessions)

  3. Load balance WebSocket connections (sticky sessions not required)

  4. Use Redis Sentinel or Cluster for Redis high availability

  5. Monitor all instances with centralized logging