prod preparations
This commit is contained in:
603
DEPLOYMENT.md
Normal file
603
DEPLOYMENT.md
Normal file
@@ -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 <your-repo-url> 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=<generate-with: openssl rand -base64 32>
|
||||
JWT_SECRET=<generate-with: openssl rand -hex 64>
|
||||
|
||||
# Add your API keys:
|
||||
TORN_API_KEY=<your-torn-api-key>
|
||||
FFSCOUTER_KEY=<your-ffscouter-key>
|
||||
DISCORD_TOKEN=<your-discord-bot-token>
|
||||
ALLOWED_CHANNEL_ID=<your-discord-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 <repo> 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`
|
||||
Reference in New Issue
Block a user