docker-deployment-guide

Guide for docker-deployment-guide

Docker Deployment Guide

For: Legends of Himavat - Production Deployment
Target: 2500 Concurrent Users
Stack: Docker Compose (Kubernetes NOT required)
Last Updated: 2026-01-05

šŸ“‹ OVERVIEW

This guide covers production deployment using Docker Compose. For 2500 CCU, Docker Compose is recommended over Kubernetes due to:
  • āœ… Simpler architecture
  • āœ… Lower operational complexity
  • āœ… Easier debugging
  • āœ… No orchestration overhead
Kubernetes is NOT needed until 5000+ CCU or multi-region deployment.
Prerequisites:
  • Game server provisioned (8 cores, 32GB RAM)
  • SSH access to server
  • Docker and Docker Compose installed
  • Domain configured (see cloudflare-deployment-guide.md)
Estimated Time: 2-3 hours

ARCHITECTURE OVERVIEW

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  Cloudflare Tunnel (cloudflared)    │
│  wss://game.yourdomain.com          │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
               │
               ↓
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  Docker Compose Stack                │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”  │
│  │  Game Server Container         │  │
│  │  - Rust binary (legends_client)│  │
│  │  - Port 3000 (WebSocket)       │  │
│  │  - Env: PRODUCTION             │  │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜  │
│               │                       │
│               ↓                       │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”  │
│  │  PostgreSQL Container          │  │
│  │  - Port 5432 (internal only)   │  │
│  │  - Persistent volume           │  │
│  │  - Auto backups                │  │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

STEP 1: SERVER SETUP (30 minutes)

1.1 Install Docker

# Update system
sudo apt update && sudo apt upgrade -y

# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Add user to docker group (avoid sudo)
sudo usermod -aG docker $USER
newgrp docker

# Verify installation
docker --version
Expected: Docker version 24.x.x

1.2 Install Docker Compose

# Download Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# Make executable
sudo chmod +x /usr/local/bin/docker-compose

# Verify
docker-compose --version
Expected: Docker Compose version 2.x.x

STEP 2: PROJECT STRUCTURE (15 minutes)

2.1 Create Deployment Directory

# Create directory structure
mkdir -p /opt/loh-game/{config,data,backups,logs}
cd /opt/loh-game

2.2 Directory Layout

/opt/loh-game/
ā”œā”€ā”€ docker-compose.prod.yml    # Production compose file
ā”œā”€ā”€ .env.production             # Environment variables (secrets)
ā”œā”€ā”€ config/
│   ā”œā”€ā”€ postgres.conf           # PostgreSQL configuration
│   └── backup.sh               # Automated backup script
ā”œā”€ā”€ data/
│   ā”œā”€ā”€ postgres/               # Database volume (persistent)
│   └── game-data/              # Game data files (JSON)
ā”œā”€ā”€ backups/
│   └── postgres/               # Database backups
└── logs/
    ā”œā”€ā”€ game-server/            # Game server logs
    └── postgres/               # Database logs

STEP 3: CREATE DOCKER COMPOSE FILE (30 minutes)

3.1 Create Production Compose File

nano docker-compose.prod.yml

3.2 Docker Compose Configuration

version: '3.8'

services:
  # PostgreSQL Database
  postgres:
    image: postgres:15-alpine
    container_name: loh-postgres
    restart: unless-stopped
    
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C"
      
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
      - ./config/postgres.conf:/etc/postgresql/postgresql.conf:ro
      - ./backups/postgres:/backups
      
    ports:
      - "127.0.0.1:5432:5432"  # Only accessible from localhost
      
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
      
    command: postgres -c config_file=/etc/postgresql/postgresql.conf
    
    networks:
      - loh-network
      
  # Game Server
  game-server:
    image: loh-game:latest
    container_name: loh-game-server
    restart: unless-stopped
    
    depends_on:
      postgres:
        condition: service_healthy
        
    environment:
      # Game Configuration
      RUST_LOG: ${RUST_LOG:-info}
      RUST_BACKTRACE: ${RUST_BACKTRACE:-0}
      
      # Network
      GAME_SERVER_URL: ${GAME_SERVER_URL}
      BIND_ADDRESS: "0.0.0.0:3000"
      
      # Database
      DATABASE_URL: "postgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME}"
      DATABASE_MAX_CONNECTIONS: 100
      
      # Security
      JWT_SECRET: ${JWT_SECRET}
      PASSWORD_SALT: ${PASSWORD_SALT}
      
      # Monitoring
      SENTRY_DSN: ${SENTRY_DSN}
      ENVIRONMENT: production
      
    volumes:
      - ./data/game-data:/app/data:ro  # Game data files (read-only)
      - ./logs/game-server:/app/logs   # Log output
      
    ports:
      - "127.0.0.1:3000:3000"  # Only accessible from localhost (via Cloudflare Tunnel)
      
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
      
    networks:
      - loh-network
      
    # Resource limits
    deploy:
      resources:
        limits:
          cpus: '7'      # Leave 1 core for system
          memory: 28G    # Leave 4GB for system + DB
        reservations:
          cpus: '4'
          memory: 16G

networks:
  loh-network:
    driver: bridge

STEP 4: ENVIRONMENT CONFIGURATION (20 minutes)

4.1 Create Environment File

nano .env.production

4.2 Environment Variables

# Database Configuration
DB_USER=loh_admin
DB_PASSWORD=<GENERATE_SECURE_PASSWORD>  # Use: openssl rand -base64 32
DB_NAME=loh_production

# Game Server
GAME_SERVER_URL=wss://game.yourdomain.com/ws
RUST_LOG=info,loh_game=debug
RUST_BACKTRACE=1

# Security
JWT_SECRET=<GENERATE_SECRET>  # Use: openssl rand -base64 64
PASSWORD_SALT=<GENERATE_SALT>  # Use: openssl rand -base64 32

# Monitoring
SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id

# Performance
MAX_CONCURRENT_CONNECTIONS=2500

4.3 Secure Environment File

# Set proper permissions (only owner can read)
chmod 600 .env.production

# Verify
ls -la .env.production
Expected: -rw------- 1 user user

STEP 5: POSTGRESQL CONFIGURATION (30 minutes)

5.1 Create PostgreSQL Config

nano config/postgres.conf

5.2 PostgreSQL Settings (Optimized for 2500 CCU)

# Connection Settings
max_connections = 200
superuser_reserved_connections = 3

# Memory Settings
shared_buffers = 4GB                   # 25% of system RAM (16GB DB allocation)
effective_cache_size = 12GB            # 75% of system RAM
work_mem = 20MB                        # Per query operation
maintenance_work_mem = 1GB

# Write-Ahead Logging (WAL)
wal_buffers = 16MB
min_wal_size = 1GB
max_wal_size = 4GB
checkpoint_completion_target = 0.9

# Query Planner
random_page_cost = 1.1                 # SSD optimization
effective_io_concurrency = 200         # SSD optimization

# Logging
log_destination = 'stderr'
logging_collector = on
log_directory = '/var/log/postgresql'
log_filename = 'postgresql-%Y-%m-%d.log'
log_rotation_age = 1d
log_rotation_size = 100MB
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_min_duration_statement = 1000      # Log queries > 1 second

# Performance
enable_partitionwise_join = on
enable_partitionwise_aggregate = on

# SSL (if using)
ssl = on
ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem'
ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'

STEP 6: BUILD GAME SERVER IMAGE (45 minutes)

6.1 Create Dockerfile (if not exists)

cd /path/to/loh-game
nano Dockerfile.prod

6.2 Production Dockerfile

# Build stage
FROM rust:1.75-slim as builder

WORKDIR /app

# Install build dependencies
RUN apt-get update && apt-get install -y \
    pkg-config \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

# Copy manifests
COPY Cargo.toml Cargo.lock ./

# Copy source code
COPY src ./src
COPY data ./data

# Build release binary
RUN cargo build --release --bin legends_client

# Runtime stage
FROM debian:bookworm-slim

WORKDIR /app

# Install runtime dependencies
RUN apt-get update && apt-get install -y \
    ca-certificates \
    libssl3 \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Copy binary from builder
COPY --from=builder /app/target/release/legends_client /app/legends_client
COPY --from=builder /app/data /app/data

# Create non-root user
RUN useradd -m -u 1000 gameserver && \
    chown -R gameserver:gameserver /app

USER gameserver

# Health check endpoint
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

EXPOSE 3000

CMD ["/app/legends_client"]

6.3 Build Image

# Build production image
docker build -f Dockerfile.prod -t loh-game:latest .

# Tag with version
docker tag loh-game:latest loh-game:v1.0.0

# Verify image
docker images | grep loh-game

STEP 7: DATABASE BACKUP AUTOMATION (30 minutes)

7.1 Create Backup Script

nano config/backup.sh

7.2 Backup Script

#!/bin/bash
set -e

# Configuration
BACKUP_DIR="/opt/loh-game/backups/postgres"
CONTAINER_NAME="loh-postgres"
DB_NAME="loh_production"
RETENTION_DAYS=30

# Create backup filename with timestamp
BACKUP_FILE="$BACKUP_DIR/backup_$(date +%Y%m%d_%H%M%S).sql.gz"

# Perform backup
docker exec -t $CONTAINER_NAME pg_dump -U loh_admin -d $DB_NAME | gzip > $BACKUP_FILE

# Verify backup
if [ -f "$BACKUP_FILE" ]; then
    echo "Backup successful: $BACKUP_FILE"
    
    # Get backup size
    SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
    echo "Backup size: $SIZE"
else
    echo "Backup failed!"
    exit 1
fi

# Clean old backups (older than RETENTION_DAYS)
find $BACKUP_DIR -name "backup_*.sql.gz" -type f -mtime +$RETENTION_DAYS -delete
echo "Old backups cleaned (retention: $RETENTION_DAYS days)"

# Upload to S3 (optional - uncomment if using)
# aws s3 cp $BACKUP_FILE s3://your-bucket/loh-backups/

7.3 Make Executable and Schedule

# Make executable
chmod +x config/backup.sh

# Test backup
./config/backup.sh

# Add to crontab (daily at 2 AM)
crontab -e

# Add line:
0 2 * * * /opt/loh-game/config/backup.sh >> /opt/loh-game/logs/backup.log 2>&1

STEP 8: DEPLOY STACK (20 minutes)

8.1 Start Services

cd /opt/loh-game

# Pull/verify images
docker-compose -f docker-compose.prod.yml pull

# Start stack (detached mode)
docker-compose -f docker-compose.prod.yml up -d

# Watch logs
docker-compose -f docker-compose.prod.yml logs -f

8.2 Verify Deployment

# Check running containers
docker ps

# Expected output:
# loh-game-server  (healthy)
# loh-postgres     (healthy)

# Check health
docker-compose -f docker-compose.prod.yml ps

8.3 Test Database Connection

# Connect to PostgreSQL
docker exec -it loh-postgres psql -U loh_admin -d loh_production

# Run test query
SELECT version();

# Exit
\q

STEP 9: MONITORING & LOGGING (30 minutes)

9.1 View Logs

# Real-time logs (all services)
docker-compose -f docker-compose.prod.yml logs -f

# Game server logs only
docker-compose -f docker-compose.prod.yml logs -f game-server

# Database logs
docker-compose -f docker-compose.prod.yml logs -f postgres

# Last 100 lines
docker-compose -f docker-compose.prod.yml logs --tail=100

9.2 Set Up Log Rotation

# Create logrotate config
sudo nano /etc/logrotate.d/loh-game
/opt/loh-game/logs/game-server/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 gameserver gameserver
}

/opt/loh-game/logs/postgres/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
}

9.3 Resource Monitoring

# Container stats (CPU, RAM, Network)
docker stats

# Specific container
docker stats loh-game-server

STEP 10: MAINTENANCE PROCEDURES

10.1 Update Game Server

cd /path/to/loh-game

# Pull latest code
git pull origin main

# Rebuild image
docker build -f Dockerfile.prod -t loh-game:latest .

# Restart with zero downtime (if using multiple instances)
docker-compose -f docker-compose.prod.yml up -d --no-deps --build game-server

10.2 Database Maintenance

# Vacuum database (reclaim space)
docker exec loh-postgres psql -U loh_admin -d loh_production -c "VACUUM VERBOSE ANALYZE;"

# Check database size
docker exec loh-postgres psql -U loh_admin -d loh_production -c "SELECT pg_size_pretty(pg_database_size('loh_production'));"

10.3 Restart Services

# Restart all services
docker-compose -f docker-compose.prod.yml restart

# Restart specific service
docker-compose -f docker-compose.prod.yml restart game-server

# Stop all services
docker-compose -f docker-compose.prod.yml down

# Start services
docker-compose -f docker-compose.prod.yml up -d

TROUBLESHOOTING

Issue: Game Server Won't Start

Check logs:
docker-compose -f docker-compose.prod.yml logs game-server
Common fixes:
  1. Database not ready: docker-compose ps - ensure postgres is healthy
  2. Environment variables missing: Check .env.production
  3. Port conflict: sudo lsof -i :3000 - kill conflicting process
  4. Image not built: docker images | grep loh-game

Issue: Database Connection Failed

Check database:
# Database health
docker exec loh-postgres pg_isready -U loh_admin

# Connection test
docker exec loh-postgres psql -U loh_admin -l
Common fixes:
  1. Wrong credentials: Verify DB_USER, DB_PASSWORD in .env.production
  2. Database not initialized: docker-compose logs postgres
  3. Network issue: docker network ls - ensure loh-network exists

Issue: High Memory Usage

Check stats:
docker stats --no-stream
Solutions:
  1. Reduce shared_buffers in postgres.conf
  2. Lower work_mem in postgres.conf
  3. Adjust resource limits in docker-compose.yml
  4. Check for memory leaks: docker exec loh-game-server ps aux

SCALING TO 5000+ CCU

When you need to scale beyond 2500 CCU:

Option 1: Vertical Scaling (up to ~5000 CCU)

  • Upgrade server: 16 cores, 64 GB RAM
  • Update resource limits in docker-compose.yml
  • Increase PostgreSQL max_connections to 400

Option 2: Horizontal Scaling (5000+ CCU)

  • Add second game server
  • Use load balancer (Cloudflare Load Balancing)
  • Shared PostgreSQL with read replicas
  • At this point, consider Kubernetes

KUBERNETES MIGRATION PATH

When to migrate: 10,000+ CCU or multi-region
What changes:
  1. Replace docker-compose.yml → Kubernetes manifests
  2. Game server → Deployment (replicas: 3+)
  3. PostgreSQL → StatefulSet (or managed service)
  4. Cloudflare Tunnel → Kubernetes Ingress
  5. Add: Horizontal Pod Autoscaler (HPA)
Complexity increase: ~3x operational overhead

SUCCESS CHECKLIST

  • Docker and Docker Compose installed
  • docker-compose.prod.yml created
  • .env.production configured with secrets
  • PostgreSQL optimized for 2500 CCU
  • Game server image built
  • Automated backups configured (daily cron)
  • Services started and healthy
  • Database connection verified
  • Logs accessible and rotating
  • Resource monitoring working
  • Maintenance procedures documented

COST COMPARISON

SolutionSetup TimeMonthly CostOperational Complexity
Docker Compose (2500 CCU)3 hours~$280Low ⭐
Kubernetes (2500 CCU)16+ hours~$450+High ⭐⭐⭐⭐
Kubernetes (10k+ CCU)16+ hours~$800+High ⭐⭐⭐⭐
Recommendation: Stick with Docker Compose until 5000+ CCU.

NEXT STEPS

After completing Docker deployment:
  1. āœ… Return to consolidated_tasks.md → Agent 1, Phase 2 (mark database tasks complete)
  2. āœ… Complete Cloudflare Tunnel setup (see cloudflare-deployment-guide.md)
  3. āœ… Configure monitoring (Phase 3)
  4. āœ… Set up CI/CD for automated image builds
Reference Files:
  • cloudflare-deployment-guide.md - Cloudflare Tunnel setup
  • infrastructure-specs.md - Server specifications
  • security-infrastructure-todo.md - Full deployment checklist

Document Version: 1.0
Last Tested: 2026-01-05
Docker Version: 24.x
Docker Compose Version: 2.x