\!DOCTYPE html>
This guide covers best practices for deploying Mail-Rulez in production environments.
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
}
}
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";
}
}
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
# docker-compose.yml
services:
mail-rulez:
networks:
- internal
- web
caddy:
networks:
- web
networks:
internal:
internal: true
web:
external: true
# 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
# UFW example
ufw allow 80/tcp
ufw allow 443/tcp
ufw deny 5001/tcp # Block direct access
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
}
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
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
# Regular maintenance
docker exec mail-rulez sqlite3 /app/data/mail_rulez.db "VACUUM;"
docker exec mail-rulez sqlite3 /app/data/mail_rulez.db "ANALYZE;"
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 |
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
For high-volume deployments:
# docker-compose.yml
services:
mail-rulez:
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
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
}
}
# 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
# 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
# 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;"
# 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
# Check memory consumers
docker exec mail-rulez ps aux --sort=-%mem | head
# Restart workers
docker exec mail-rulez supervisorctl restart all
# 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 ..."
# Test internal connectivity
docker exec mail-rulez curl -v http://localhost:5001/health
# Check firewall rules
iptables -L -n | grep 5001