# 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://discord.com/developers/applications): - `https://gameplay.sba.manticorum.com/api/auth/discord/callback/server` ### 2. Database Setup ```bash # 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 ```bash ssh akamai mkdir -p ~/container-data/strat-gameplay-webapp cd ~/container-data/strat-gameplay-webapp ``` ### Step 2: Clone Repository ```bash 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`): ```bash # 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`): ```bash # 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`: ```yaml # 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 ```bash # 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 ```bash 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 ```bash # 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 ```bash 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 ```bash # Check previous commits git log --oneline -10 # Rollback to specific commit git checkout # 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 ```bash # 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_IDS` for 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: 1. **Vertical**: Upgrade Linode plan (easy, immediate) 2. **Database**: Migrate to managed PostgreSQL (Linode, Neon, Supabase) 3. **Horizontal**: Add second app server behind load balancer 4. **CDN**: Cloudflare for static assets and DDoS protection