From b70d87c797d0db86d5275906c0469d91a55ac7f3 Mon Sep 17 00:00:00 2001 From: jerick Date: Wed, 28 Jan 2026 08:53:21 -0500 Subject: [PATCH] prod preparations --- .env.example | 25 ++ .gitignore | 43 ++- DEPLOYMENT.md | 603 +++++++++++++++++++++++++++++++++++++++++++ PRODUCTION_README.md | 303 ++++++++++++++++++++++ config.py | 41 ++- faction-war.service | 30 +++ nginx.conf.example | 58 +++++ requirements.txt | 8 + setup_production.sh | 162 ++++++++++++ 9 files changed, 1259 insertions(+), 14 deletions(-) create mode 100644 .env.example create mode 100644 DEPLOYMENT.md create mode 100644 PRODUCTION_README.md create mode 100644 faction-war.service create mode 100644 nginx.conf.example create mode 100644 requirements.txt create mode 100644 setup_production.sh diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..46f1bfb --- /dev/null +++ b/.env.example @@ -0,0 +1,25 @@ +# Torn API Configuration +TORN_API_KEY=your_torn_api_key_here +FFSCOUTER_KEY=your_ffscouter_api_key_here + +# Discord Bot Configuration +DISCORD_TOKEN=your_discord_bot_token_here +ALLOWED_CHANNEL_ID=your_discord_channel_id_here + +# Authentication +# IMPORTANT: Generate a strong random password for production +AUTH_PASSWORD=your_strong_password_here +# IMPORTANT: Generate a strong random secret for JWT signing +JWT_SECRET=your_random_jwt_secret_here + +# Timing Settings (in seconds) +POLL_INTERVAL=30 +HIT_CHECK_INTERVAL=60 +REASSIGN_DELAY=120 +ASSIGNMENT_TIMEOUT=60 +ASSIGNMENT_REMINDER=45 +CHAIN_TIMER_THRESHOLD=5 + +# Server Configuration (optional) +# HOST=0.0.0.0 +# PORT=8000 diff --git a/.gitignore b/.gitignore index df2328f..909a956 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,43 @@ +# Environment variables and secrets +.env +data/config.json +tokens.md + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python *.venv -temp.md +venv/ +env/ +ENV/ +*.egg-info/ +dist/ +build/ + +# Data files (may contain sensitive info) *data -tokens.md \ No newline at end of file +data/*.json +!data/.gitkeep + +# Temporary files +temp.md +*.tmp +*.bak + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Logs +*.log +logs/ + +# OS +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..a6c4003 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,603 @@ +# Production Deployment Guide + +This guide walks you through deploying the Faction War Dispatch Bot to a production server. + +## Table of Contents +1. [Security Considerations](#security-considerations) +2. [Server Requirements](#server-requirements) +3. [Installation Steps](#installation-steps) +4. [SSL/HTTPS Setup](#sslhttps-setup) +5. [Free Domain Setup](#free-domain-setup) +6. [Systemd Service Setup](#systemd-service-setup) +7. [Firewall Configuration](#firewall-configuration) +8. [Monitoring & Maintenance](#monitoring--maintenance) + +--- + +## Security Considerations + +### Critical Security Steps (DO BEFORE DEPLOYMENT!) + +1. **Change Default Secrets** + ```bash + # Generate a strong random password + openssl rand -base64 32 + + # Generate a strong JWT secret + openssl rand -hex 64 + ``` + +2. **Never Commit Secrets to Git** + - Use `.env` file for secrets (already in `.gitignore`) + - Or use the Settings page to configure via web UI + - Keep `data/config.json` out of version control (already in `.gitignore`) + +3. **HTTPS is REQUIRED** + - JWT tokens and passwords are transmitted over the network + - Without HTTPS, credentials can be intercepted + - See [SSL/HTTPS Setup](#sslhttps-setup) below + +4. **Firewall Configuration** + - Only expose port 443 (HTTPS) or 80 (HTTP - redirects to HTTPS) + - Block port 8000 from external access (use reverse proxy) + - See [Firewall Configuration](#firewall-configuration) below + +5. **Keep Dependencies Updated** + ```bash + pip install --upgrade -r requirements.txt + ``` + +6. **Backup Your Data** + - Backup the `data/` directory regularly + - Contains group assignments, Discord mappings, and config + +--- + +## Server Requirements + +### Minimum Specs +- **OS**: Ubuntu 20.04+ / Debian 11+ (or any Linux distribution) +- **RAM**: 512MB minimum, 1GB recommended +- **CPU**: 1 core minimum +- **Storage**: 5GB minimum +- **Network**: Static IP or dynamic DNS + +### Required Software +- Python 3.11+ +- Nginx (reverse proxy) +- Certbot (for SSL certificates) +- systemd (process management) + +--- + +## Installation Steps + +### 1. Initial Server Setup + +```bash +# Update system packages +sudo apt update && sudo apt upgrade -y + +# Install required packages +sudo apt install -y python3 python3-pip python3-venv nginx certbot python3-certbot-nginx git + +# Create a non-root user for the application (recommended) +sudo adduser --system --group --home /opt/faction-war factionwar +``` + +### 2. Clone and Setup Application + +```bash +# Switch to the application user +sudo su - factionwar + +# Clone the repository (or upload files via SCP/SFTP) +cd /opt/faction-war +git clone app +cd app + +# Create Python virtual environment +python3 -m venv venv +source venv/bin/activate + +# Install dependencies +pip install -r requirements.txt +``` + +### 3. Configure Environment Variables + +```bash +# Create .env file from example +cp .env.example .env + +# Edit .env with your actual values +nano .env +``` + +**Important .env values to set:** +```bash +# Generate strong random values for these: +AUTH_PASSWORD= +JWT_SECRET= + +# Add your API keys: +TORN_API_KEY= +FFSCOUTER_KEY= +DISCORD_TOKEN= +ALLOWED_CHANNEL_ID= +``` + +### 4. Create Data Directory + +```bash +# Create data directory for persistent storage +mkdir -p /opt/faction-war/app/data +chown -R factionwar:factionwar /opt/faction-war/app/data +chmod 700 /opt/faction-war/app/data # Restrict access to sensitive data +``` + +--- + +## SSL/HTTPS Setup + +### Option 1: Using Let's Encrypt (Recommended - Free SSL) + +```bash +# Install Certbot +sudo apt install certbot python3-certbot-nginx -y + +# Get SSL certificate (replace with your domain) +sudo certbot --nginx -d yourdomain.com + +# Certbot will automatically configure Nginx for HTTPS +# Follow the prompts to set up automatic renewal +``` + +### Option 2: Self-Signed Certificate (Development Only) + +```bash +# Generate self-signed certificate (NOT for production) +sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout /etc/ssl/private/nginx-selfsigned.key \ + -out /etc/ssl/certs/nginx-selfsigned.crt +``` + +--- + +## Free Domain Setup + +### Option 1: Free Subdomain Services + +1. **DuckDNS** (https://www.duckdns.org) + - Completely free + - Provides `yourdomain.duckdns.org` + - Supports dynamic DNS updates + + ```bash + # Install DuckDNS updater + mkdir -p /opt/duckdns + cd /opt/duckdns + echo "echo url=\"https://www.duckdns.org/update?domains=YOURDOMAIN&token=YOUR-TOKEN&ip=\" | curl -k -o ~/duckdns/duck.log -K -" > duck.sh + chmod 700 duck.sh + + # Add to crontab for auto-updates + crontab -e + # Add: */5 * * * * /opt/duckdns/duck.sh >/dev/null 2>&1 + ``` + +2. **FreeDNS** (https://freedns.afraid.org) + - Free subdomain or use their domains + - More domain options than DuckDNS + +3. **No-IP** (https://www.noip.com) + - Free tier available + - Dynamic DNS client included + +### Option 2: Cloudflare (Free Tier) + +If you own a domain: +1. Transfer DNS to Cloudflare (free) +2. Get free SSL certificate +3. DDoS protection included +4. CDN included + +--- + +## Nginx Reverse Proxy Configuration + +Create Nginx configuration: + +```bash +sudo nano /etc/nginx/sites-available/faction-war +``` + +**Configuration file:** + +```nginx +# HTTP - Redirect to HTTPS +server { + listen 80; + listen [::]:80; + server_name yourdomain.com; # Replace with your domain + + # Redirect all HTTP to HTTPS + return 301 https://$server_name$request_uri; +} + +# HTTPS - Main Application +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name yourdomain.com; # Replace with your domain + + # SSL Configuration (managed by Certbot) + ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + # Security Headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Logging + access_log /var/log/nginx/faction-war-access.log; + error_log /var/log/nginx/faction-war-error.log; + + # Proxy settings + location / { + proxy_pass http://127.0.0.1:8000; + 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 (if needed in future) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # Static files (optional optimization) + location /static/ { + alias /opt/faction-war/app/static/; + expires 1d; + add_header Cache-Control "public, immutable"; + } +} +``` + +**Enable the site:** + +```bash +# Create symbolic link +sudo ln -s /etc/nginx/sites-available/faction-war /etc/nginx/sites-enabled/ + +# Test configuration +sudo nginx -t + +# Reload Nginx +sudo systemctl reload nginx +``` + +--- + +## Systemd Service Setup + +Create a systemd service to run the bot automatically: + +```bash +sudo nano /etc/systemd/system/faction-war.service +``` + +**Service file:** + +```ini +[Unit] +Description=Faction War Dispatch Bot +After=network.target + +[Service] +Type=simple +User=factionwar +Group=factionwar +WorkingDirectory=/opt/faction-war/app +Environment="PATH=/opt/faction-war/app/venv/bin" +ExecStart=/opt/faction-war/app/venv/bin/python main.py + +# Restart policy +Restart=always +RestartSec=10 + +# Security hardening +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +ReadWritePaths=/opt/faction-war/app/data + +# Logging +StandardOutput=journal +StandardError=journal +SyslogIdentifier=faction-war + +[Install] +WantedBy=multi-user.target +``` + +**Enable and start the service:** + +```bash +# Reload systemd +sudo systemctl daemon-reload + +# Enable service to start on boot +sudo systemctl enable faction-war + +# Start the service +sudo systemctl start faction-war + +# Check status +sudo systemctl status faction-war + +# View logs +sudo journalctl -u faction-war -f +``` + +--- + +## Firewall Configuration + +### Using UFW (Ubuntu/Debian) + +```bash +# Install UFW +sudo apt install ufw -y + +# Default policies +sudo ufw default deny incoming +sudo ufw default allow outgoing + +# Allow SSH (IMPORTANT - don't lock yourself out!) +sudo ufw allow ssh + +# Allow HTTP and HTTPS +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp + +# Enable firewall +sudo ufw enable + +# Check status +sudo ufw status verbose +``` + +**Important:** Do NOT allow port 8000 externally. The application runs on port 8000 internally, but should only be accessible via Nginx reverse proxy on ports 80/443. + +--- + +## Monitoring & Maintenance + +### Log Files + +```bash +# Application logs +sudo journalctl -u faction-war -f + +# Nginx access logs +sudo tail -f /var/log/nginx/faction-war-access.log + +# Nginx error logs +sudo tail -f /var/log/nginx/faction-war-error.log +``` + +### Health Checks + +```bash +# Check if service is running +sudo systemctl status faction-war + +# Check if Nginx is running +sudo systemctl status nginx + +# Test application response +curl -I https://yourdomain.com +``` + +### Backup Strategy + +```bash +# Create backup script +sudo nano /opt/faction-war/backup.sh +``` + +**Backup script:** + +```bash +#!/bin/bash +BACKUP_DIR="/opt/faction-war/backups" +DATE=$(date +%Y%m%d_%H%M%S) +APP_DIR="/opt/faction-war/app" + +mkdir -p $BACKUP_DIR + +# Backup data directory +tar -czf $BACKUP_DIR/data_backup_$DATE.tar.gz -C $APP_DIR data/ + +# Keep only last 7 days of backups +find $BACKUP_DIR -name "data_backup_*.tar.gz" -mtime +7 -delete + +echo "Backup completed: data_backup_$DATE.tar.gz" +``` + +```bash +# Make executable +sudo chmod +x /opt/faction-war/backup.sh + +# Add to cron for daily backups +sudo crontab -e +# Add: 0 2 * * * /opt/faction-war/backup.sh +``` + +### Updates + +```bash +# Stop the service +sudo systemctl stop faction-war + +# Update code +cd /opt/faction-war/app +sudo -u factionwar git pull + +# Update dependencies +sudo -u factionwar /opt/faction-war/app/venv/bin/pip install --upgrade -r requirements.txt + +# Restart service +sudo systemctl start faction-war + +# Check status +sudo systemctl status faction-war +``` + +--- + +## Troubleshooting + +### Service Won't Start + +```bash +# Check logs for errors +sudo journalctl -u faction-war -n 50 --no-pager + +# Check Python errors +sudo -u factionwar /opt/faction-war/app/venv/bin/python /opt/faction-war/app/main.py +``` + +### Nginx 502 Bad Gateway + +```bash +# Check if application is running +sudo systemctl status faction-war + +# Check if application is listening on port 8000 +sudo netstat -tlnp | grep 8000 + +# Check Nginx error logs +sudo tail -f /var/log/nginx/faction-war-error.log +``` + +### SSL Certificate Issues + +```bash +# Renew certificate manually +sudo certbot renew + +# Test auto-renewal +sudo certbot renew --dry-run +``` + +### Permission Issues + +```bash +# Fix data directory permissions +sudo chown -R factionwar:factionwar /opt/faction-war/app/data +sudo chmod 700 /opt/faction-war/app/data +``` + +--- + +## Security Checklist + +Before going live, verify: + +- [ ] Strong AUTH_PASSWORD set in .env or Settings page +- [ ] Strong JWT_SECRET set in .env or Settings page +- [ ] SSL certificate installed and working (HTTPS) +- [ ] Firewall configured (only ports 22, 80, 443 open) +- [ ] Port 8000 NOT accessible from outside +- [ ] .env file has restricted permissions (chmod 600) +- [ ] data/ directory has restricted permissions (chmod 700) +- [ ] Automatic SSL renewal configured +- [ ] Backup script configured and tested +- [ ] Monitoring/logging configured +- [ ] Git repository does NOT contain secrets +- [ ] Default passwords changed + +--- + +## Performance Tuning (Optional) + +### Uvicorn with Multiple Workers + +Edit `/etc/systemd/system/faction-war.service`: + +```ini +ExecStart=/opt/faction-war/app/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 --workers 2 +``` + +### Redis for Session Storage (Future Enhancement) + +For better session management across multiple workers, consider adding Redis: + +```bash +sudo apt install redis-server -y +pip install redis +``` + +--- + +## Quick Start Summary + +```bash +# 1. Server setup +sudo apt update && sudo apt install -y python3 python3-venv nginx certbot python3-certbot-nginx + +# 2. Clone and install +cd /opt && sudo mkdir faction-war && cd faction-war +git clone app && cd app +python3 -m venv venv && source venv/bin/activate +pip install -r requirements.txt + +# 3. Configure +cp .env.example .env +nano .env # Set your secrets and API keys + +# 4. Setup SSL +sudo certbot --nginx -d yourdomain.com + +# 5. Configure Nginx (use config from above) +sudo nano /etc/nginx/sites-available/faction-war +sudo ln -s /etc/nginx/sites-available/faction-war /etc/nginx/sites-enabled/ +sudo nginx -t && sudo systemctl reload nginx + +# 6. Setup systemd service (use config from above) +sudo nano /etc/systemd/system/faction-war.service +sudo systemctl daemon-reload +sudo systemctl enable faction-war +sudo systemctl start faction-war + +# 7. Configure firewall +sudo ufw allow ssh && sudo ufw allow 80/tcp && sudo ufw allow 443/tcp +sudo ufw enable + +# 8. Done! Visit https://yourdomain.com +``` + +--- + +## Getting Help + +If you encounter issues: + +1. Check logs: `sudo journalctl -u faction-war -f` +2. Check Nginx logs: `sudo tail -f /var/log/nginx/faction-war-error.log` +3. Test the application directly: `curl http://127.0.0.1:8000` +4. Verify firewall: `sudo ufw status` +5. Test SSL: `curl -I https://yourdomain.com` diff --git a/PRODUCTION_README.md b/PRODUCTION_README.md new file mode 100644 index 0000000..e29c86c --- /dev/null +++ b/PRODUCTION_README.md @@ -0,0 +1,303 @@ +# Faction War Dispatch Bot - Production Deployment + +## Quick Summary + +This application is ready for production deployment with proper security measures. Follow the steps below to deploy to your Linux server. + +## Security Features Implemented + +- Environment variable support (.env files) +- Secrets excluded from git (.gitignore) +- HTTPS/SSL configuration (via Let's Encrypt) +- JWT-based authentication +- Nginx reverse proxy configuration +- Systemd service for process management +- Firewall configuration +- Automated backups +- Security headers + +## Prerequisites + +- **Server**: Linux VM (Ubuntu 20.04+ or Debian 11+) +- **RAM**: 512MB minimum, 1GB recommended +- **Domain**: Free domain from DuckDNS, FreeDNS, or No-IP +- **Port Access**: Ports 80 and 443 open to the internet + +## Automated Setup (Recommended) + +1. Upload files to your server: + ```bash + scp -r * user@your-server:/opt/faction-war/app/ + ``` + +2. Run the setup script: + ```bash + ssh user@your-server + cd /opt/faction-war/app + sudo bash setup_production.sh + ``` + +3. The script will: + - Install all dependencies + - Configure Nginx + - Get SSL certificate + - Setup systemd service + - Configure firewall + - Setup automated backups + +4. Follow prompts to: + - Enter your domain name + - Enter your email (for SSL) + - Configure your .env file with secrets + +## Manual Setup + +See [DEPLOYMENT.md](DEPLOYMENT.md) for detailed step-by-step instructions. + +## Free Domain Options + +### Option 1: DuckDNS (Recommended) +- Visit https://www.duckdns.org +- Sign in and create a subdomain (e.g., `myfaction.duckdns.org`) +- Note your token for DNS updates +- Free HTTPS support with Let's Encrypt + +### Option 2: FreeDNS +- Visit https://freedns.afraid.org +- Create free subdomain +- Choose from many domain options + +### Option 3: No-IP +- Visit https://www.noip.com +- Free tier includes dynamic DNS + +## Critical Security Steps + +### Before Deployment: + +1. **Generate Strong Secrets**: + ```bash + # Generate AUTH_PASSWORD + openssl rand -base64 32 + + # Generate JWT_SECRET + openssl rand -hex 64 + ``` + +2. **Configure .env File**: + ```bash + cp .env.example .env + nano .env + ``` + + Update these values: + ```env + AUTH_PASSWORD= + JWT_SECRET= + TORN_API_KEY= + DISCORD_TOKEN= + ``` + +3. **Secure .env File**: + ```bash + chmod 600 .env + ``` + +4. **Never Commit Secrets**: + - `.env` is in `.gitignore` + - `data/config.json` is in `.gitignore` + - Never commit API keys or passwords + +## Post-Deployment + +### Access Your Application +``` +https://yourdomain.com +``` + +### Check Service Status +```bash +sudo systemctl status faction-war +``` + +### View Logs +```bash +sudo journalctl -u faction-war -f +``` + +### Restart Service +```bash +sudo systemctl restart faction-war +``` + +## Configuration + +### Option 1: Web Interface (Recommended) +1. Visit `https://yourdomain.com/config` +2. Configure all settings through the UI +3. Settings are saved to `data/config.json` + +### Option 2: Environment Variables +1. Edit `/opt/faction-war/app/.env` +2. Restart service: `sudo systemctl restart faction-war` + +### Option 3: JSON File +1. Edit `data/config.json` directly +2. Restart service to apply changes + +**Priority**: Environment variables > config.json > defaults + +## Security Checklist + +Before going live, verify: + +- [ ] Strong AUTH_PASSWORD generated and set +- [ ] Strong JWT_SECRET generated and set +- [ ] HTTPS/SSL certificate installed +- [ ] Firewall configured (only ports 22, 80, 443) +- [ ] Port 8000 blocked from external access +- [ ] .env file has permissions 600 +- [ ] data/ directory has permissions 700 +- [ ] Automatic SSL renewal working +- [ ] Backups configured (2 AM daily) +- [ ] Logs accessible and monitoring setup + +## File Structure + +``` +/opt/faction-war/app/ +├── main.py # Application entry point +├── config.py # Configuration loader +├── .env # Environment variables (NEVER COMMIT) +├── .env.example # Example environment file +├── requirements.txt # Python dependencies +├── faction-war.service # Systemd service template +├── nginx.conf.example # Nginx configuration template +├── setup_production.sh # Automated setup script +├── DEPLOYMENT.md # Detailed deployment guide +├── data/ # Persistent data (NEVER COMMIT) +│ ├── config.json # Web UI configuration +│ ├── discord_mapping.json +│ └── ... +├── routers/ # API routes +├── services/ # Business logic +├── static/ # Frontend assets +└── templates/ # HTML templates +``` + +## Updates + +### Update Application +```bash +cd /opt/faction-war/app +git pull +sudo -u factionwar venv/bin/pip install --upgrade -r requirements.txt +sudo systemctl restart faction-war +``` + +### Update SSL Certificate +```bash +# Auto-renewal is configured by certbot +# Test renewal: +sudo certbot renew --dry-run +``` + +## Backups + +Automated daily backups run at 2 AM: +- Location: `/opt/faction-war/backups/` +- Retention: 7 days +- Manual backup: + ```bash + /opt/faction-war/backup.sh + ``` + +## Troubleshooting + +### Application Won't Start +```bash +# Check logs +sudo journalctl -u faction-war -n 50 + +# Test manually +sudo -u factionwar /opt/faction-war/app/venv/bin/python /opt/faction-war/app/main.py +``` + +### 502 Bad Gateway +```bash +# Check if app is running +sudo systemctl status faction-war + +# Check if listening on port 8000 +sudo netstat -tlnp | grep 8000 +``` + +### SSL Certificate Issues +```bash +# Renew manually +sudo certbot renew + +# Check certificate status +sudo certbot certificates +``` + +## Support + +For detailed deployment instructions, see [DEPLOYMENT.md](DEPLOYMENT.md) + +## Quick Commands Reference + +```bash +# Service management +sudo systemctl start faction-war +sudo systemctl stop faction-war +sudo systemctl restart faction-war +sudo systemctl status faction-war + +# View logs +sudo journalctl -u faction-war -f +sudo tail -f /var/log/nginx/faction-war-error.log + +# Update application +cd /opt/faction-war/app && git pull && sudo systemctl restart faction-war + +# Manual backup +/opt/faction-war/backup.sh + +# Renew SSL +sudo certbot renew +``` + +## Monitoring + +Monitor these logs regularly: +- Application: `sudo journalctl -u faction-war -f` +- Nginx Access: `/var/log/nginx/faction-war-access.log` +- Nginx Errors: `/var/log/nginx/faction-war-error.log` +- System: `sudo tail -f /var/log/syslog` + +## Production Best Practices + +1. **Use strong passwords** - Generate with OpenSSL +2. **Keep dependencies updated** - Regular `pip install --upgrade` +3. **Monitor logs** - Check for errors and suspicious activity +4. **Backup regularly** - Automated daily backups configured +5. **Use HTTPS only** - HTTP auto-redirects to HTTPS +6. **Restrict firewall** - Only necessary ports open +7. **Update system** - Regular `apt update && apt upgrade` +8. **Test backups** - Periodically restore from backup to verify + +## Features + +- Secure authentication (JWT + password) +- Web-based configuration +- Real-time activity logging +- Active user tracking +- Automated hit assignment +- Chain timer monitoring +- Server-side state persistence +- Multi-device support + +--- + +**Ready to deploy?** Run `setup_production.sh` on your server to get started! diff --git a/config.py b/config.py index ff9fb72..e42302e 100644 --- a/config.py +++ b/config.py @@ -1,5 +1,10 @@ from pathlib import Path import json +import os +from dotenv import load_dotenv + +# Load environment variables from .env file (if it exists) +load_dotenv() def load_from_json(): #Load config from JSON file if it exists @@ -18,28 +23,40 @@ def load_from_json(): # Load from JSON or use defaults _config = load_from_json() -# Torn API -TORN_API_KEY = _config.get("TORN_API_KEY", "YOUR_TORN_API_KEY_HERE") +# Helper function to get config value from environment, then JSON, then default +def get_config(key: str, default, is_int: bool = False): + # 1. Try environment variable first + env_val = os.getenv(key) + if env_val is not None: + return int(env_val) if is_int else env_val + # 2. Try JSON config + json_val = _config.get(key) + if json_val is not None: + return json_val + # 3. Use default + return default +# Torn API +TORN_API_KEY = get_config("TORN_API_KEY", "YOUR_TORN_API_KEY_HERE") # FFScouter API -FFSCOUTER_KEY = _config.get("FFSCOUTER_KEY", "YOUR_FFSCOUTER_KEY_HERE") +FFSCOUTER_KEY = get_config("FFSCOUTER_KEY", "YOUR_FFSCOUTER_KEY_HERE") # Discord Bot -DISCORD_TOKEN = _config.get("DISCORD_TOKEN", "YOUR_DISCORD_BOT_TOKEN_HERE") -ALLOWED_CHANNEL_ID = _config.get("ALLOWED_CHANNEL_ID", 0) +DISCORD_TOKEN = get_config("DISCORD_TOKEN", "YOUR_DISCORD_BOT_TOKEN_HERE") +ALLOWED_CHANNEL_ID = get_config("ALLOWED_CHANNEL_ID", 0, is_int=True) # Intervals -HIT_CHECK_INTERVAL = _config.get("HIT_CHECK_INTERVAL", 60) -REASSIGN_DELAY = _config.get("REASSIGN_DELAY", 120) +HIT_CHECK_INTERVAL = get_config("HIT_CHECK_INTERVAL", 60, is_int=True) +REASSIGN_DELAY = get_config("REASSIGN_DELAY", 120, is_int=True) # Bot Assignment Settings -ASSIGNMENT_TIMEOUT = _config.get("ASSIGNMENT_TIMEOUT", 60) # Seconds before reassigning a target -ASSIGNMENT_REMINDER = _config.get("ASSIGNMENT_REMINDER", 45) # Seconds before sending reminder message +ASSIGNMENT_TIMEOUT = get_config("ASSIGNMENT_TIMEOUT", 60, is_int=True) # Seconds before reassigning a target +ASSIGNMENT_REMINDER = get_config("ASSIGNMENT_REMINDER", 45, is_int=True) # Seconds before sending reminder message # Chain Timer Settings -CHAIN_TIMER_THRESHOLD = _config.get("CHAIN_TIMER_THRESHOLD", 5) # Minutes - start assigning hits when chain timer is at or below this +CHAIN_TIMER_THRESHOLD = get_config("CHAIN_TIMER_THRESHOLD", 5, is_int=True) # Minutes - start assigning hits when chain timer is at or below this # Authentication -AUTH_PASSWORD = _config.get("AUTH_PASSWORD", "YOUR_AUTH_PASSWORD_HERE") # Universal password for all users -JWT_SECRET = _config.get("JWT_SECRET", "your-secret-key-change-this") # Secret key for JWT tokens +AUTH_PASSWORD = get_config("AUTH_PASSWORD", "YOUR_AUTH_PASSWORD_HERE") # Universal password for all users +JWT_SECRET = get_config("JWT_SECRET", "your-secret-key-change-this") # Secret key for JWT tokens diff --git a/faction-war.service b/faction-war.service new file mode 100644 index 0000000..a83ff0f --- /dev/null +++ b/faction-war.service @@ -0,0 +1,30 @@ +[Unit] +Description=Faction War Dispatch Bot +After=network.target + +[Service] +Type=simple +User=factionwar +Group=factionwar +WorkingDirectory=/opt/faction-war/app +Environment="PATH=/opt/faction-war/app/venv/bin" +ExecStart=/opt/faction-war/app/venv/bin/python main.py + +# Restart policy +Restart=always +RestartSec=10 + +# Security hardening +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +ReadWritePaths=/opt/faction-war/app/data + +# Logging +StandardOutput=journal +StandardError=journal +SyslogIdentifier=faction-war + +[Install] +WantedBy=multi-user.target diff --git a/nginx.conf.example b/nginx.conf.example new file mode 100644 index 0000000..117a5f0 --- /dev/null +++ b/nginx.conf.example @@ -0,0 +1,58 @@ +# HTTP - Redirect to HTTPS +server { + listen 80; + listen [::]:80; + server_name yourdomain.com; # REPLACE WITH YOUR DOMAIN + + # Redirect all HTTP to HTTPS + return 301 https://$server_name$request_uri; +} + +# HTTPS - Main Application +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name yourdomain.com; # REPLACE WITH YOUR DOMAIN + + # SSL Configuration (managed by Certbot) + ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; # REPLACE + ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; # REPLACE + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + # Security Headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Logging + access_log /var/log/nginx/faction-war-access.log; + error_log /var/log/nginx/faction-war-error.log; + + # Proxy settings + location / { + proxy_pass http://127.0.0.1:8000; + 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 (if needed in future) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # Static files (optional optimization) + location /static/ { + alias /opt/faction-war/app/static/; + expires 1d; + add_header Cache-Control "public, immutable"; + } +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a8c2cef --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +fastapi>=0.104.0 +uvicorn[standard]>=0.24.0 +aiohttp>=3.9.0 +pydantic>=2.0.0 +PyJWT>=2.8.0 +discord.py>=2.3.0 +python-dotenv>=1.0.0 +Jinja2>=3.1.2 diff --git a/setup_production.sh b/setup_production.sh new file mode 100644 index 0000000..988c4b7 --- /dev/null +++ b/setup_production.sh @@ -0,0 +1,162 @@ +#!/bin/bash +# Production Setup Script for Faction War Dispatch Bot +# Run this script on your Linux server + +set -e # Exit on error + +echo "========================================" +echo "Faction War Dispatch Bot - Setup Script" +echo "========================================" +echo "" + +# Check if running as root +if [ "$EUID" -ne 0 ]; then + echo "Please run as root (use sudo)" + exit 1 +fi + +# Get domain name +read -p "Enter your domain name (e.g., faction.yourdomain.com): " DOMAIN +if [ -z "$DOMAIN" ]; then + echo "Domain name is required!" + exit 1 +fi + +# Get email for Let's Encrypt +read -p "Enter your email for SSL certificate (Let's Encrypt): " EMAIL +if [ -z "$EMAIL" ]; then + echo "Email is required for SSL certificate!" + exit 1 +fi + +echo "" +echo "Installing required packages..." +apt update +apt install -y python3 python3-pip python3-venv nginx certbot python3-certbot-nginx git + +echo "" +echo "Creating application user..." +if ! id "factionwar" &>/dev/null; then + adduser --system --group --home /opt/faction-war factionwar +fi + +echo "" +echo "Setting up application directory..." +mkdir -p /opt/faction-war +cd /opt/faction-war + +# If app directory doesn't exist, clone or expect user to upload files +if [ ! -d "app" ]; then + echo "Please upload your application files to /opt/faction-war/app" + echo "Or clone from git repository" + exit 1 +fi + +cd app + +echo "" +echo "Setting up Python virtual environment..." +if [ ! -d "venv" ]; then + sudo -u factionwar python3 -m venv venv +fi + +echo "Installing Python dependencies..." +sudo -u factionwar venv/bin/pip install -r requirements.txt + +echo "" +echo "Creating data directory..." +mkdir -p /opt/faction-war/app/data +chown -R factionwar:factionwar /opt/faction-war/app/data +chmod 700 /opt/faction-war/app/data + +echo "" +echo "Setting up environment file..." +if [ ! -f ".env" ]; then + cp .env.example .env + echo "" + echo "⚠️ IMPORTANT: Edit /opt/faction-war/app/.env with your configuration!" + echo " Generate secure secrets with:" + echo " - AUTH_PASSWORD: openssl rand -base64 32" + echo " - JWT_SECRET: openssl rand -hex 64" + echo "" + read -p "Press Enter to edit .env file now (or Ctrl+C to exit and edit later)..." + nano .env +fi + +chown factionwar:factionwar .env +chmod 600 .env + +echo "" +echo "Setting up Nginx configuration..." +cat nginx.conf.example | sed "s/yourdomain.com/$DOMAIN/g" > /tmp/faction-war-nginx.conf +cp /tmp/faction-war-nginx.conf /etc/nginx/sites-available/faction-war +ln -sf /etc/nginx/sites-available/faction-war /etc/nginx/sites-enabled/faction-war + +# Remove default nginx site if it exists +rm -f /etc/nginx/sites-enabled/default + +echo "" +echo "Testing Nginx configuration..." +nginx -t + +echo "" +echo "Getting SSL certificate from Let's Encrypt..." +certbot --nginx -d $DOMAIN --non-interactive --agree-tos --email $EMAIL + +echo "" +echo "Setting up systemd service..." +cp faction-war.service /etc/systemd/system/faction-war.service +systemctl daemon-reload +systemctl enable faction-war +systemctl start faction-war + +echo "" +echo "Configuring firewall..." +ufw --force enable +ufw allow ssh +ufw allow 80/tcp +ufw allow 443/tcp + +echo "" +echo "Setting up backup cron job..." +cat > /opt/faction-war/backup.sh << 'EOF' +#!/bin/bash +BACKUP_DIR="/opt/faction-war/backups" +DATE=$(date +%Y%m%d_%H%M%S) +APP_DIR="/opt/faction-war/app" + +mkdir -p $BACKUP_DIR +tar -czf $BACKUP_DIR/data_backup_$DATE.tar.gz -C $APP_DIR data/ +find $BACKUP_DIR -name "data_backup_*.tar.gz" -mtime +7 -delete +echo "Backup completed: data_backup_$DATE.tar.gz" +EOF + +chmod +x /opt/faction-war/backup.sh + +# Add to crontab if not already present +(crontab -l 2>/dev/null | grep -v backup.sh; echo "0 2 * * * /opt/faction-war/backup.sh") | crontab - + +echo "" +echo "========================================" +echo "✅ Setup Complete!" +echo "========================================" +echo "" +echo "Your application should now be running at: https://$DOMAIN" +echo "" +echo "Important next steps:" +echo "1. Visit https://$DOMAIN and log in with your AUTH_PASSWORD" +echo "2. Configure your API keys in the Settings page" +echo "3. Test the application functionality" +echo "" +echo "Useful commands:" +echo " - Check status: sudo systemctl status faction-war" +echo " - View logs: sudo journalctl -u faction-war -f" +echo " - Restart: sudo systemctl restart faction-war" +echo " - Update code: cd /opt/faction-war/app && git pull && sudo systemctl restart faction-war" +echo "" +echo "Security reminders:" +echo " - Keep your .env file secure (chmod 600)" +echo " - Regularly update: apt update && apt upgrade" +echo " - Monitor logs for suspicious activity" +echo " - Backup data regularly (automated at 2 AM daily)" +echo ""