Deployment Guide - RumenDamyanov/js-chess GitHub Wiki

Deployment Guide

Deploy your JS Chess application to production with proper configuration, security, and monitoring.

Overview

This guide covers deploying the JS Chess project using Docker containers, configuring Nginx as a reverse proxy, and setting up production environments.

Production Architecture

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Load Balancer │ -> │   Nginx Proxy   │ -> │   Frontend      │
│   (Optional)    │    │   Port 80/443   │    │   Port 3000     │
└─────────────────┘    └─────────────────┘    └─────────────────┘
                                |
                         ┌─────────────────┐
                         │   Go Backend    │
                         │   Port 8080     │
                         └─────────────────┘

Prerequisites

  • Docker and Docker Compose installed
  • Domain name pointed to your server
  • SSL certificate (Let's Encrypt recommended)
  • At least 1GB RAM, 1 CPU core
  • 10GB disk space

Production Deployment

1. Clone and Setup

git clone --recursive https://github.com/RumenDamyanov/js-chess.git
cd js-chess
make setup

2. Environment Configuration

Create production environment file:

cp .env.example .env.production

Edit .env.production:

NODE_ENV=production
API_URL=https://api.yourdomain.com
FRONTEND_URL=https://yourdomain.com
SSL_ENABLED=true
DOMAIN=yourdomain.com
[email protected]

3. SSL Certificate Setup

Using Let's Encrypt with Certbot:

# Install certbot
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx

# Get SSL certificate
sudo certbot --nginx -d yourdomain.com -d api.yourdomain.com

# Auto-renewal
sudo crontab -e
# Add: 0 12 * * * /usr/bin/certbot renew --quiet

4. Production Build

# Build all components
make build-prod

# Start production stack
make deploy-prod

Docker Production Configuration

Docker Compose Production

Create docker-compose.prod.yml:

version: '3.8'

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/prod.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/ssl
    restart: unless-stopped
    depends_on:
      - frontend
      - backend

  frontend:
    build:
      context: .
      dockerfile: Dockerfile.prod
    environment:
      - NODE_ENV=production
    restart: unless-stopped
    expose:
      - "3000"

  backend:
    image: rumenx/go-chess:latest
    environment:
      - GIN_MODE=release
      - PORT=8080
    restart: unless-stopped
    expose:
      - "8080"

  redis:
    image: redis:alpine
    restart: unless-stopped
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data

volumes:
  redis_data:

Production Dockerfile

# Multi-stage build
FROM node:18-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

# Production image
FROM nginx:alpine

COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx/default.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Nginx Configuration

Main Configuration

Create nginx/prod.conf:

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    # Logging
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css application/json application/javascript;

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/m;
    limit_req_zone $binary_remote_addr zone=general:10m rate=100r/m;

    # Frontend server
    server {
        listen 80;
        listen [::]:80;
        server_name yourdomain.com;

        # Redirect HTTP to HTTPS
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name yourdomain.com;

        # SSL configuration
        ssl_certificate /etc/ssl/certs/yourdomain.com.crt;
        ssl_certificate_key /etc/ssl/private/yourdomain.com.key;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;

        # Security headers
        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

        # Frontend files
        location / {
            proxy_pass http://frontend:3000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        # API proxy
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            proxy_pass http://backend:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        # WebSocket proxy
        location /ws/ {
            proxy_pass http://backend:8080;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        # Static assets caching
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }

        # Health check
        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }
    }
}

Environment-Specific Configurations

Development Environment

# Development with hot reload
make dev

# Development with Docker
make dev-docker

Staging Environment

# Staging deployment
make deploy-staging

# Staging tests
make test-staging

Production Environment

# Production deployment
make deploy-prod

# Production health check
make health-prod

# Production logs
make logs-prod

Security Configuration

Firewall Setup

# UFW firewall configuration
sudo ufw enable
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Fail2ban for additional protection
sudo apt-get install fail2ban

Environment Variables

Store sensitive data in environment variables:

# Database (if using)
DB_HOST=localhost
DB_USER=chess_user
DB_PASSWORD=secure_password
DB_NAME=chess_db

# API Keys
JWT_SECRET=your_jwt_secret_here
REDIS_URL=redis://localhost:6379

# Monitoring
SENTRY_DSN=your_sentry_dsn

Docker Secrets

For sensitive data in Docker:

services:
  backend:
    image: rumenx/go-chess:latest
    secrets:
      - db_password
      - jwt_secret

secrets:
  db_password:
    file: ./secrets/db_password.txt
  jwt_secret:
    file: ./secrets/jwt_secret.txt

Monitoring and Logging

Health Checks

# Check all services
make health-check

# Individual service checks
curl https://yourdomain.com/health
curl https://api.yourdomain.com/health

Log Management

# View logs
make logs

# Follow logs
make logs-follow

# Log rotation
sudo logrotate -f /etc/logrotate.d/nginx

Monitoring Setup

Add monitoring with Prometheus and Grafana:

services:
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml

  grafana:
    image: grafana/grafana
    ports:
      - "3001:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin

Performance Optimization

CDN Configuration

Use a CDN for static assets:

# CDN headers
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    add_header CDN-Cache-Control "public, max-age=31536000";
}

Database Optimization

If using a database:

-- Create indexes for better performance
CREATE INDEX idx_games_created_at ON games(created_at);
CREATE INDEX idx_moves_game_id ON moves(game_id);

Caching Strategy

Implement Redis caching:

// Cache game states
func (s *GameService) GetGame(id int) (*Game, error) {
    // Check cache first
    if cached := s.cache.Get(fmt.Sprintf("game:%d", id)); cached != nil {
        return cached.(*Game), nil
    }

    // Fetch from database
    game, err := s.db.GetGame(id)
    if err != nil {
        return nil, err
    }

    // Cache result
    s.cache.Set(fmt.Sprintf("game:%d", id), game, 5*time.Minute)
    return game, nil
}

Backup and Recovery

Database Backup

# Automated backup script
#!/bin/bash
BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d_%H%M%S)

# PostgreSQL backup
pg_dump chess_db > $BACKUP_DIR/chess_db_$DATE.sql

# Compress and encrypt
tar -czf $BACKUP_DIR/chess_backup_$DATE.tar.gz $BACKUP_DIR/chess_db_$DATE.sql
gpg --encrypt --recipient [email protected] $BACKUP_DIR/chess_backup_$DATE.tar.gz

# Clean old backups
find $BACKUP_DIR -name "chess_backup_*.tar.gz.gpg" -mtime +30 -delete

Disaster Recovery

# Full system restore
make restore-from-backup

# Database restore
pg_restore -d chess_db backup_file.sql

Continuous Deployment

GitHub Actions

Create .github/workflows/deploy.yml:

name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          submodules: recursive

      - name: Deploy to server
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /opt/js-chess
            git pull --recurse-submodules
            make deploy-prod

Rolling Updates

# Zero-downtime deployment
make deploy-rolling

# Rollback if needed
make rollback

Troubleshooting

Common Issues

  1. SSL Certificate Issues

    # Renew certificate
    sudo certbot renew
    
    # Test certificate
    sudo nginx -t
    sudo systemctl reload nginx
    
  2. Container Issues

    # Check container status
    docker ps -a
    
    # View container logs
    docker logs container_name
    
    # Restart services
    make restart-prod
    
  3. Performance Issues

    # Monitor resource usage
    htop
    docker stats
    
    # Check Nginx status
    sudo systemctl status nginx
    

Log Analysis

# Analyze access logs
tail -f /var/log/nginx/access.log | grep -v "200"

# Error log analysis
tail -f /var/log/nginx/error.log

# Application logs
docker logs js-chess_backend_1 --follow

Maintenance

Regular Tasks

# Daily maintenance
make daily-maintenance

# Weekly maintenance
make weekly-maintenance

# Monthly maintenance
make monthly-maintenance

Updates

# Update system packages
sudo apt update && sudo apt upgrade

# Update Docker images
make update-images

# Update application
git pull --recurse-submodules
make deploy-prod

For more detailed deployment information, see the Advanced Deployment guide.