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>
294 lines
8.6 KiB
Markdown
294 lines
8.6 KiB
Markdown
# 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 <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
|
|
```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 |