<\!DOCTYPE html> Production Deployment Guide

Production Deployment Guide

This guide covers best practices for deploying Mail-Rulez in production environments.

Prerequisites

  • Docker 20.10+ and Docker Compose 1.29+
  • Domain name with DNS control (for hosted version)
  • SSL certificates (automatic with Caddy)
  • Minimum 2GB RAM, 20GB storage
  • Backup strategy in place

Deployment Options

Option 1: Docker Compose (Recommended)

Create a production docker-compose.yml:

version: '3.8'

services:
  mail-rulez:
    image: ghcr.io/real-pm/mail-rulez:latest
    container_name: mail-rulez-prod
    ports:
      - "127.0.0.1:5001:5001"  # Bind to localhost only
    environment:
      - FLASK_ENV=production
      - MASTER_KEY=${MASTER_KEY}  # Generate with: openssl rand -hex 32
      - SECRET_KEY=${SECRET_KEY}  # Generate with: openssl rand -hex 32
    volumes:
      - mail_rulez_data:/app/data
      - mail_rulez_logs:/app/logs
      - mail_rulez_config:/app/config
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5001/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          cpus: '0.5'
          memory: 512M

  # Reverse proxy with automatic SSL
  caddy:
    image: caddy:latest
    container_name: caddy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    restart: unless-stopped

volumes:
  mail_rulez_data:
  mail_rulez_logs:
  mail_rulez_config:
  caddy_data:
  caddy_config:

Create Caddyfile:

your-domain.com {
    reverse_proxy mail-rulez-prod:5001
    
    # Security headers
    header {
        X-Content-Type-Options nosniff
        X-Frame-Options DENY
        X-XSS-Protection "1; mode=block"
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        Referrer-Policy "strict-origin-when-cross-origin"
    }
    
    # Compression
    encode gzip
    
    # Logging
    log {
        output file /data/access.log
        format json
    }
}

Option 2: Docker with External Reverse Proxy

If using Nginx/Apache:

docker run -d \
  --name mail-rulez \
  --restart unless-stopped \
  -p 127.0.0.1:5001:5001 \
  -e FLASK_ENV=production \
  -e MASTER_KEY=$(openssl rand -hex 32) \
  -v /opt/mail-rulez/data:/app/data \
  -v /opt/mail-rulez/logs:/app/logs \
  -v /opt/mail-rulez/config:/app/config \
  ghcr.io/real-pm/mail-rulez:latest

Nginx configuration:

server {
    listen 443 ssl http2;
    server_name your-domain.com;
    
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    
    location / {
        proxy_pass http://127.0.0.1:5001;
        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 support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Security Hardening

1. Environment Variables

Never commit secrets. Use .env file:

# .env (add to .gitignore)
MASTER_KEY=your-generated-master-key
SECRET_KEY=your-generated-secret-key
FLASK_SECRET_KEY=your-flask-secret

Generate secure keys:

# Generate keys
echo "MASTER_KEY=$(openssl rand -hex 32)" >> .env
echo "SECRET_KEY=$(openssl rand -hex 32)" >> .env
echo "FLASK_SECRET_KEY=$(openssl rand -hex 32)" >> .env

2. Network Security

# docker-compose.yml
services:
  mail-rulez:
    networks:
      - internal
      - web
    
  caddy:
    networks:
      - web

networks:
  internal:
    internal: true
  web:
    external: true

3. File Permissions

# Set proper ownership
docker exec mail-rulez chown -R app:app /app/data /app/config /app/logs

# Restrict permissions
docker exec mail-rulez chmod 700 /app/data /app/config
docker exec mail-rulez chmod 755 /app/logs

4. Firewall Rules

# UFW example
ufw allow 80/tcp
ufw allow 443/tcp
ufw deny 5001/tcp  # Block direct access

Monitoring and Logging

1. Log Rotation

Create /etc/logrotate.d/mail-rulez:

/opt/mail-rulez/logs/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 app app
    postrotate
        docker exec mail-rulez kill -USR1 1
    endscript
}

2. Health Monitoring

Set up monitoring with your preferred tool:

# Uptime monitoring
curl -f https://your-domain.com/health || alert

# Container monitoring
docker stats mail-rulez --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"

# Disk usage monitoring
df -h /opt/mail-rulez

3. Backup Strategy

Automated backup script:

#!/bin/bash
# /opt/mail-rulez/backup.sh

BACKUP_DIR="/backup/mail-rulez"
DATE=$(date +%Y%m%d_%H%M%S)

# Stop processing to ensure consistency
docker exec mail-rulez supervisorctl stop email_processor

# Backup data
docker run --rm -v mail_rulez_data:/data -v $BACKUP_DIR:/backup \
  alpine tar czf /backup/mail-rulez-$DATE.tar.gz -C /data .

# Backup database
docker exec mail-rulez sqlite3 /app/data/mail_rulez.db ".backup /app/data/backup-$DATE.db"

# Resume processing
docker exec mail-rulez supervisorctl start email_processor

# Cleanup old backups (keep 30 days)
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete

Add to cron:

0 2 * * * /opt/mail-rulez/backup.sh

Performance Optimization

1. Database Optimization

# Regular maintenance
docker exec mail-rulez sqlite3 /app/data/mail_rulez.db "VACUUM;"
docker exec mail-rulez sqlite3 /app/data/mail_rulez.db "ANALYZE;"

2. Resource Tuning

Based on your email volume:

| Daily Emails | CPU | RAM | Batch Size | Workers | |--------------|-----|-----|------------|---------| | < 1,000 | 0.5 | 512MB | 100 | 1 | | 1,000-10,000 | 1.0 | 1GB | 100 | 2 | | 10,000-50,000| 2.0 | 2GB | 200 | 4 | | > 50,000 | 4.0 | 4GB | 500 | 8 |

3. Caching

Enable Redis for session caching:

services:
  redis:
    image: redis:alpine
    restart: unless-stopped
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes
    
  mail-rulez:
    environment:
      - REDIS_URL=redis://redis:6379/0

Scaling Strategies

Horizontal Scaling

For high-volume deployments:

# docker-compose.yml
services:
  mail-rulez:
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure

Load Balancing

With Caddy:

your-domain.com {
    reverse_proxy mail-rulez-1:5001 mail-rulez-2:5001 mail-rulez-3:5001 {
        lb_policy least_conn
        health_uri /health
        health_interval 10s
    }
}

Disaster Recovery

1. Backup Restoration

# Stop container
docker stop mail-rulez

# Restore data
docker run --rm -v mail_rulez_data:/data -v /backup:/backup \
  alpine tar xzf /backup/mail-rulez-20240101_020000.tar.gz -C /data

# Start container
docker start mail-rulez

2. Migration to New Server

# On old server
docker save ghcr.io/real-pm/mail-rulez:latest | gzip > mail-rulez.tar.gz
docker run --rm -v mail_rulez_data:/data alpine tar czf data-backup.tar.gz -C /data .

# On new server
docker load < mail-rulez.tar.gz
docker volume create mail_rulez_data
docker run --rm -v mail_rulez_data:/data -v $(pwd):/backup alpine tar xzf /backup/data-backup.tar.gz -C /data

Maintenance Tasks

Weekly Maintenance

# Check disk usage
df -h /opt/mail-rulez

# Review error logs
docker exec mail-rulez tail -n 100 /app/logs/errors.log

# Database optimization
docker exec mail-rulez sqlite3 /app/data/mail_rulez.db "PRAGMA optimize;"

Monthly Maintenance

# Update container
docker pull ghcr.io/real-pm/mail-rulez:latest
docker-compose up -d

# Security updates
docker exec mail-rulez pip list --outdated

# Review access logs
docker exec caddy cat /data/access.log | jq '.status' | sort | uniq -c

Troubleshooting Production Issues

High Memory Usage

# Check memory consumers
docker exec mail-rulez ps aux --sort=-%mem | head

# Restart workers
docker exec mail-rulez supervisorctl restart all

Slow Response Times

# Check database size
docker exec mail-rulez ls -lh /app/data/*.db

# Analyze slow queries
docker exec mail-rulez sqlite3 /app/data/mail_rulez.db "EXPLAIN QUERY PLAN SELECT ..."

Connection Issues

# Test internal connectivity
docker exec mail-rulez curl -v http://localhost:5001/health

# Check firewall rules
iptables -L -n | grep 5001

Related Documentation