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
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 --versionExpected:
Docker version 24.x.x1.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 --versionExpected:
Docker Compose version 2.x.xSTEP 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-game2.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 logsSTEP 3: CREATE DOCKER COMPOSE FILE (30 minutes)
3.1 Create Production Compose File
nano docker-compose.prod.yml3.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: bridgeSTEP 4: ENVIRONMENT CONFIGURATION (20 minutes)
4.1 Create Environment File
nano .env.production4.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=25004.3 Secure Environment File
# Set proper permissions (only owner can read)
chmod 600 .env.production
# Verify
ls -la .env.productionExpected:
-rw------- 1 user userSTEP 5: POSTGRESQL CONFIGURATION (30 minutes)
5.1 Create PostgreSQL Config
nano config/postgres.conf5.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.prod6.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-gameSTEP 7: DATABASE BACKUP AUTOMATION (30 minutes)
7.1 Create Backup Script
nano config/backup.sh7.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>&1STEP 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 -f8.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 ps8.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
\qSTEP 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=1009.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-serverSTEP 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-server10.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 -dTROUBLESHOOTING
Issue: Game Server Won't Start
Check logs:
docker-compose -f docker-compose.prod.yml logs game-serverCommon fixes:
- Database not ready:
docker-compose ps- ensure postgres is healthy - Environment variables missing: Check
.env.production - Port conflict:
sudo lsof -i :3000- kill conflicting process - 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 -lCommon fixes:
- Wrong credentials: Verify DB_USER, DB_PASSWORD in
.env.production - Database not initialized:
docker-compose logs postgres - Network issue:
docker network ls- ensure loh-network exists
Issue: High Memory Usage
Check stats:
docker stats --no-streamSolutions:
- Reduce
shared_buffersin postgres.conf - Lower
work_memin postgres.conf - Adjust resource limits in docker-compose.yml
- 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_connectionsto 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:
- Replace docker-compose.yml ā Kubernetes manifests
- Game server ā Deployment (replicas: 3+)
- PostgreSQL ā StatefulSet (or managed service)
- Cloudflare Tunnel ā Kubernetes Ingress
- 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
Recommendation: Stick with Docker Compose until 5000+ CCU.
NEXT STEPS
After completing Docker deployment:
- ā
Return to
consolidated_tasks.mdā Agent 1, Phase 2 (mark database tasks complete) - ā
Complete Cloudflare Tunnel setup (see
cloudflare-deployment-guide.md) - ā Configure monitoring (Phase 3)
- ā Set up CI/CD for automated image builds
Reference Files:
cloudflare-deployment-guide.md- Cloudflare Tunnel setupinfrastructure-specs.md- Server specificationssecurity-infrastructure-todo.md- Full deployment checklist
Document Version: 1.0
Last Tested: 2026-01-05
Docker Version: 24.x
Docker Compose Version: 2.x
Last Tested: 2026-01-05
Docker Version: 24.x
Docker Compose Version: 2.x