Documents deployment strategy using Docker Compose on existing Linode infrastructure. Includes architecture diagram, step-by-step deployment guide, NPM configuration, maintenance commands, and rollback procedures. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
8.6 KiB
8.6 KiB
Production Deployment Guide
Target Environment
Server: Linode VPS (ssh akamai)
- Ubuntu 24.04 LTS
- 8GB RAM / 160GB disk
- Docker + Nginx Proxy Manager pre-configured
Domain: gameplay.sba.manticorum.com (or similar)
Architecture
┌─────────────────────────────────────────────────────┐
│ Linode VPS │
├─────────────────────────────────────────────────────┤
│ Nginx Proxy Manager (:80/:443) │
│ └─ gameplay.sba.manticorum.com │
│ ├─ /api/* → backend:8000 │
│ ├─ /socket.io/* → backend:8000 (WebSocket) │
│ └─ /* → frontend:3000 │
├─────────────────────────────────────────────────────┤
│ strat-gameplay-webapp │
│ ├─ backend (FastAPI + Socket.io) :8000 │
│ └─ frontend-sba (Nuxt 3 SSR) :3000 │
├─────────────────────────────────────────────────────┤
│ Shared Services (existing) │
│ ├─ sba_postgres :5432 (database: sba_gameplay) │
│ └─ sba_redis :6379 │
└─────────────────────────────────────────────────────┘
Why Docker Compose?
Evaluated options for this deployment:
| Option | Verdict | Reason |
|---|---|---|
| Docker Compose | ✅ Selected | Existing infra, compose files ready, NPM network integration |
| Bare metal (systemd) | ❌ | No isolation, manual dependency management, harder rollbacks |
| Docker Swarm | ❌ | Overkill for single node |
| Kubernetes/K3s | ❌ | Significant complexity for minimal benefit at this scale |
Pre-Deployment Checklist
1. Discord OAuth Setup
- Add redirect URI in Discord Developer Portal:
https://gameplay.sba.manticorum.com/api/auth/discord/callback/server
2. Database Setup
# SSH to server
ssh akamai
# Create database
docker exec -it sba_postgres psql -U sba -c "CREATE DATABASE sba_gameplay;"
3. DNS Configuration
- Add A record:
gameplay.sba.manticorum.com→ Linode IP
Deployment Steps
Step 1: Prepare Server Directory
ssh akamai
mkdir -p ~/container-data/strat-gameplay-webapp
cd ~/container-data/strat-gameplay-webapp
Step 2: Clone Repository
git clone https://github.com/calcorum/strat-gameplay-webapp.git .
# Or use deploy key for private repo
Step 3: Create Production Environment Files
Backend (backend/.env):
# Database - use existing SBA postgres
DATABASE_URL=postgresql+asyncpg://sba:PASSWORD@sba_postgres:5432/sba_gameplay
# Security
SECRET_KEY=generate-a-secure-64-char-key-here
# Discord OAuth
DISCORD_CLIENT_ID=your-client-id
DISCORD_CLIENT_SECRET=your-client-secret
DISCORD_SERVER_REDIRECT_URI=https://gameplay.sba.manticorum.com/api/auth/discord/callback/server
FRONTEND_URL=https://gameplay.sba.manticorum.com
# CORS
CORS_ORIGINS=["https://gameplay.sba.manticorum.com"]
# Redis - use existing SBA redis
REDIS_URL=redis://sba_redis:6379
# League APIs
SBA_API_URL=https://api.sba.manticorum.com
SBA_API_KEY=your-sba-api-key
# Access Control (empty = all users, or comma-separated Discord IDs)
ALLOWED_DISCORD_IDS=
Frontend (frontend-sba/.env):
# API URLs (same domain, proxied by NPM)
NUXT_PUBLIC_API_URL=https://gameplay.sba.manticorum.com
NUXT_PUBLIC_WS_URL=https://gameplay.sba.manticorum.com
# Discord OAuth
NUXT_PUBLIC_DISCORD_CLIENT_ID=your-client-id
NUXT_PUBLIC_DISCORD_REDIRECT_URI=https://gameplay.sba.manticorum.com/auth/callback
# Internal API URL for SSR (Docker network)
NUXT_API_URL_INTERNAL=http://backend:8000
Step 4: Create Production Docker Compose Override
Create docker-compose.production.yml:
# Production overrides for Linode deployment
# Usage: docker compose -f docker-compose.yml -f docker-compose.production.yml up -d
services:
backend:
build:
context: ./backend
target: production
environment:
- APP_ENV=production
- DEBUG=false
networks:
- sba-database_default
- nginx-proxy-manager_npm_network
restart: always
# Don't expose port externally - NPM handles routing
ports: !reset []
expose:
- "8000"
frontend-sba:
build:
context: ./frontend-sba
target: production
environment:
- NODE_ENV=production
networks:
- nginx-proxy-manager_npm_network
restart: always
ports: !reset []
expose:
- "3000"
depends_on:
- backend
# Don't need local redis - use existing sba_redis
redis:
profiles:
- disabled
networks:
sba-database_default:
external: true
nginx-proxy-manager_npm_network:
external: true
Step 5: Run Database Migrations
# Build backend first
docker compose -f docker-compose.yml -f docker-compose.production.yml build backend
# Run migrations
docker compose -f docker-compose.yml -f docker-compose.production.yml run --rm backend \
alembic upgrade head
Step 6: Start Services
docker compose -f docker-compose.yml -f docker-compose.production.yml up -d
Step 7: Configure Nginx Proxy Manager
Access NPM at http://LINODE_IP:81 and create proxy host:
Proxy Host Settings:
- Domain:
gameplay.sba.manticorum.com - Scheme:
http - Forward Hostname:
strat-gameplay-webapp-frontend-sba-1 - Forward Port:
3000 - Websockets Support: ✅ Enabled
- SSL: Request new Let's Encrypt certificate
Custom Locations (for API routing):
| Location | Scheme | Forward Host | Port |
|---|---|---|---|
/api |
http | strat-gameplay-webapp-backend-1 | 8000 |
/socket.io |
http | strat-gameplay-webapp-backend-1 | 8000 |
Step 8: Verify Deployment
# Health check
curl https://gameplay.sba.manticorum.com/api/health
# Check logs
docker compose -f docker-compose.yml -f docker-compose.production.yml logs -f
Maintenance Commands
cd ~/container-data/strat-gameplay-webapp
# View logs
docker compose -f docker-compose.yml -f docker-compose.production.yml logs -f backend
docker compose -f docker-compose.yml -f docker-compose.production.yml logs -f frontend-sba
# Restart services
docker compose -f docker-compose.yml -f docker-compose.production.yml restart
# Pull updates and redeploy
git pull
docker compose -f docker-compose.yml -f docker-compose.production.yml build
docker compose -f docker-compose.yml -f docker-compose.production.yml up -d
# Run migrations after update
docker compose -f docker-compose.yml -f docker-compose.production.yml run --rm backend \
alembic upgrade head
Rollback Procedure
# Check previous commits
git log --oneline -10
# Rollback to specific commit
git checkout <commit-hash>
# Rebuild and restart
docker compose -f docker-compose.yml -f docker-compose.production.yml build
docker compose -f docker-compose.yml -f docker-compose.production.yml up -d
Monitoring
Health Endpoints
- Backend:
https://gameplay.sba.manticorum.com/api/health - Frontend:
https://gameplay.sba.manticorum.com(200 OK)
Log Locations
# Container logs
docker logs strat-gameplay-webapp-backend-1
# Application logs (if volume mounted)
~/container-data/strat-gameplay-webapp/backend/logs/
Resource Estimates
| Service | RAM | CPU | Notes |
|---|---|---|---|
| Backend | ~200MB | Low | Increases with concurrent games |
| Frontend | ~150MB | Low | Nuxt SSR |
| Total | ~350MB | Low | Well within 5.8GB available |
Security Considerations
- Use strong
SECRET_KEY(64+ characters) - Restrict
ALLOWED_DISCORD_IDSfor beta testing - SSL enforced via NPM
- Database credentials not exposed externally
- Redis not exposed externally (Docker network only)
Future Scaling Options
If load increases beyond single-server capacity:
- Vertical: Upgrade Linode plan (easy, immediate)
- Database: Migrate to managed PostgreSQL (Linode, Neon, Supabase)
- Horizontal: Add second app server behind load balancer
- CDN: Cloudflare for static assets and DDoS protection