-
Notifications
You must be signed in to change notification settings - Fork 0
deployment
Production deployment on a Linux server with Nginx, SSL (Let's Encrypt), Docker, and PM2.
ITG Media App is designed to run on a Linux server (Ubuntu 22.04/24.04 LTS recommended). This guide covers the full production deployment including SSL, domain configuration, and process management.
⚠️ Platform Note: ITG Media App has been tested on Linux servers only. Windows Server deployment has not been tested. The live instance at https://donoconnor.com runs on Ubuntu Linux.
Internet
│
▼
Cloudflare DNS (Optional — DDoS protection, CDN)
│
▼
Your Server (Ubuntu 22.04/24.04)
│
├── Nginx (443) ─── Reverse Proxy + SSL
│ │
│ ├── / → Next.js (localhost:3000)
│ ├── /api/* → Django Gunicorn (localhost:8000)
│ ├── /ws/* → Daphne WebSocket (localhost:8001)
│ ├── /admin/* → Django (IP whitelisted)
│ └── vdo.yourdomain.com → LiveKit (localhost:7880)
│
├── PM2 Process Manager
│ ├── mediasite-django (Gunicorn)
│ ├── mediasite-daphne
│ └── mediasite-nextjs
│
├── Docker Containers
│ ├── LiveKit Server
│ ├── LiveKit Egress
│ ├── LiveKit Ingress
│ └── Avatar Agent (optional)
│
├── PostgreSQL (localhost:5432)
│
└── Redis (localhost:6379)
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 2 cores | 4+ cores |
| RAM | 4 GB | 8+ GB |
| Storage | 40 GB SSD | 80+ GB SSD |
| Bandwidth | 1 TB/month | Unlimited |
| OS | Ubuntu 22.04/24.04 LTS | Ubuntu 24.04 LTS |
💡 If running the AI features (Ollama), add at least 8 GB RAM and 20 GB storage for models.
The simplest production deployment — everything in containers.
git clone https://github.com/docisit/itg-media-engine.git
cd itg-media-engine
# Configure environment
cp .env.example .env
# Edit .env with your production values# .env.docker
POSTGRES_PASSWORD=<strong-database-password>
REDIS_PASSWORD=
SECRET_KEY=<django-secret-key>
# ... (all other required variables)docker compose -f docker-compose.yml up -ddocker exec mediasite-django python manage.py migrate
docker exec -it mediasite-django python manage.py createsuperuser
docker exec mediasite-django python manage.py collectstatic --noinputFull control over each service with PM2 process management.
# Update system
sudo apt update && sudo apt upgrade -y
# Install essentials
sudo apt install -y curl wget git build-essential nginx certbot python3-certbot-nginx
# Install Node.js 20
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Install Python 3.11+
sudo apt install -y python3 python3-pip python3-venv
# Install PostgreSQL
sudo apt install -y postgresql postgresql-client
# Install Redis
sudo apt install -y redis-server
# Install Docker (for LiveKit)
sudo apt install -y docker.io docker-compose-v2
sudo systemctl enable docker
sudo systemctl start dockerFollow the Installation Guide for manual setup (Option B), then continue with this page for SSL, domain, and Nginx configuration.
Create /etc/nginx/sites-available/yourdomain.com:
# Redirect HTTP to HTTPS
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$server_name$request_uri;
}
# Main HTTPS server
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# SSL Certificates (Certbot adds these)
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Client upload size (for media uploads)
client_max_body_size 500M;
# Next.js Frontend
location / {
proxy_pass http://127.0.0.1:3000;
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;
proxy_read_timeout 86400;
}
# Django API
location /api/ {
proxy_pass http://127.0.0.1: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;
}
# Django Admin (protected at your custom ADMIN_URL)
location /admin/ {
proxy_pass http://127.0.0.1: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;
}
# Daphne WebSockets
location /ws/ {
proxy_pass http://127.0.0.1:8001;
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;
proxy_read_timeout 86400;
}
# Static files
location /static/ {
alias /home/deploy/itg-media-engine/staticfiles/;
expires 30d;
add_header Cache-Control "public, immutable";
}
# Media uploads
location /media/ {
alias /home/deploy/itg-media-engine/media/;
expires 7d;
}
}# Enable the site
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
# Test configuration
sudo nginx -t
# Reload Nginx
sudo systemctl reload nginx# Get SSL certificate (auto-configures Nginx)
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Test auto-renewal
sudo certbot renew --dry-run
# Certbot auto-renews via systemd timer — verify it's active
sudo systemctl status certbot.timerSet up a separate subdomain (e.g., vdo.yourdomain.com) for LiveKit WebRTC traffic. See the LiveKit Setup page for the full Nginx config.
# Create LiveKit Nginx config
sudo nano /etc/nginx/sites-available/vdo.yourdomain.com
# Enable and get SSL
sudo ln -s /etc/nginx/sites-available/vdo.yourdomain.com /etc/nginx/sites-enabled/
sudo certbot --nginx -d vdo.yourdomain.com# UFW (Ubuntu Firewall)
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw allow 7880/tcp # LiveKit API
sudo ufw allow 7881/tcp # WebRTC TCP fallback
sudo ufw allow 7882/udp # WebRTC ICE
sudo ufw allow 50000:60000/udp # WebRTC media
sudo ufw enable# Install PM2
npm install -g pm2
# Start services (from project root)
pm2 start ecosystem.config.js
# Save for auto-restart on boot
pm2 save
# Enable PM2 startup
pm2 startup
# Follow the printed command to complete setup
# Check status
pm2 list
pm2 logsCreate ecosystem.config.js in the project root:
module.exports = {
apps: [
{
name: 'mediasite-django',
script: '.venv/bin/gunicorn',
args: 'backend.wsgi:application --bind 127.0.0.1:8000 --workers 4 --timeout 120 --access-logfile /var/log/mediasite/gunicorn-access.log --error-logfile /var/log/mediasite/gunicorn-error.log',
cwd: '/home/deploy/itg-media-engine',
env: {
DJANGO_ENV: 'production',
},
autorestart: true,
max_restarts: 10,
min_uptime: '10s',
},
{
name: 'mediasite-daphne',
script: '.venv/bin/daphne',
args: '-b 127.0.0.1 -p 8001 backend.asgi:application',
cwd: '/home/deploy/itg-media-engine',
autorestart: true,
max_restarts: 10,
},
{
name: 'mediasite-nextjs',
script: 'node_modules/.bin/next',
args: 'start -p 3000',
cwd: '/home/deploy/itg-media-engine/frontend',
autorestart: true,
max_restarts: 10,
},
],
};Reference docker-compose.yml for full containerized deployment:
# Key services defined in docker-compose.yml:
# - nginx (production reverse proxy)
# - nextjs (Next.js frontend)
# - django (Django + Gunicorn)
# - daphne (Django Channels WebSocket)
# - postgres (PostgreSQL 16)
# - redis (Redis 7)Build and start:
docker compose -f docker-compose.yml build
docker compose -f docker-compose.yml up -d# Pull latest changes
cd itg-media-engine
git pull origin main
# Backend
source .venv/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py collectstatic --noinput
# Frontend
cd frontend
npm install
npm run build
# Restart services
pm2 restart all# PostgreSQL dump
pg_dump -U media_user -h localhost media_db > backup_$(date +%Y%m%d).sql
# Compress
gzip backup_$(date +%Y%m%d).sql
# Store off-server (S3, rsync, etc.)# PM2 handles its own log rotation
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7# Check disk usage
df -h
# Clean Docker images
docker system prune -a
# Clean old PM2 logs
pm2 flush- Server updated (
apt update && apt upgrade) - Node.js 20+ installed
- Python 3.11+ installed
- PostgreSQL 16+ installed and running
- Redis 7+ installed and running
- Docker installed (for LiveKit)
- Application cloned and configured
-
.envconfigured with production values -
DEBUG=False -
ALLOWED_HOSTSset correctly -
ADMIN_URLchanged from default -
ADMIN_IP_WHITELISTset - Migrations run
- Static files collected
- Admin user created
- Nginx configured
- SSL certificates installed (Let's Encrypt)
- LiveKit subdomain configured
- Firewall configured (UFW)
- PM2 services running
- PM2 startup enabled
- All services verified (see Installation Verification)
- Automated backups configured
- Troubleshooting & FAQ — Common issues and solutions
- Broadcasting Guide — Start your first broadcast
← Back to Wiki Home