prod preparations
This commit is contained in:
25
.env.example
Normal file
25
.env.example
Normal file
@@ -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
|
||||||
45
.gitignore
vendored
45
.gitignore
vendored
@@ -1,4 +1,43 @@
|
|||||||
*.venv
|
# Environment variables and secrets
|
||||||
temp.md
|
.env
|
||||||
*data
|
data/config.json
|
||||||
tokens.md
|
tokens.md
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
*.venv
|
||||||
|
venv/
|
||||||
|
env/
|
||||||
|
ENV/
|
||||||
|
*.egg-info/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Data files (may contain sensitive info)
|
||||||
|
*data
|
||||||
|
data/*.json
|
||||||
|
!data/.gitkeep
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
temp.md
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
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`
|
||||||
303
PRODUCTION_README.md
Normal file
303
PRODUCTION_README.md
Normal file
@@ -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=<generated-password>
|
||||||
|
JWT_SECRET=<generated-secret>
|
||||||
|
TORN_API_KEY=<your-api-key>
|
||||||
|
DISCORD_TOKEN=<your-bot-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!
|
||||||
41
config.py
41
config.py
@@ -1,5 +1,10 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Load environment variables from .env file (if it exists)
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
def load_from_json():
|
def load_from_json():
|
||||||
#Load config from JSON file if it exists
|
#Load config from JSON file if it exists
|
||||||
@@ -18,28 +23,40 @@ def load_from_json():
|
|||||||
# Load from JSON or use defaults
|
# Load from JSON or use defaults
|
||||||
_config = load_from_json()
|
_config = load_from_json()
|
||||||
|
|
||||||
# Torn API
|
# Helper function to get config value from environment, then JSON, then default
|
||||||
TORN_API_KEY = _config.get("TORN_API_KEY", "YOUR_TORN_API_KEY_HERE")
|
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 API
|
||||||
FFSCOUTER_KEY = _config.get("FFSCOUTER_KEY", "YOUR_FFSCOUTER_KEY_HERE")
|
FFSCOUTER_KEY = get_config("FFSCOUTER_KEY", "YOUR_FFSCOUTER_KEY_HERE")
|
||||||
|
|
||||||
# Discord Bot
|
# Discord Bot
|
||||||
DISCORD_TOKEN = _config.get("DISCORD_TOKEN", "YOUR_DISCORD_BOT_TOKEN_HERE")
|
DISCORD_TOKEN = get_config("DISCORD_TOKEN", "YOUR_DISCORD_BOT_TOKEN_HERE")
|
||||||
ALLOWED_CHANNEL_ID = _config.get("ALLOWED_CHANNEL_ID", 0)
|
ALLOWED_CHANNEL_ID = get_config("ALLOWED_CHANNEL_ID", 0, is_int=True)
|
||||||
|
|
||||||
# Intervals
|
# Intervals
|
||||||
HIT_CHECK_INTERVAL = _config.get("HIT_CHECK_INTERVAL", 60)
|
HIT_CHECK_INTERVAL = get_config("HIT_CHECK_INTERVAL", 60, is_int=True)
|
||||||
REASSIGN_DELAY = _config.get("REASSIGN_DELAY", 120)
|
REASSIGN_DELAY = get_config("REASSIGN_DELAY", 120, is_int=True)
|
||||||
|
|
||||||
# Bot Assignment Settings
|
# Bot Assignment Settings
|
||||||
ASSIGNMENT_TIMEOUT = _config.get("ASSIGNMENT_TIMEOUT", 60) # Seconds before reassigning a target
|
ASSIGNMENT_TIMEOUT = get_config("ASSIGNMENT_TIMEOUT", 60, is_int=True) # Seconds before reassigning a target
|
||||||
ASSIGNMENT_REMINDER = _config.get("ASSIGNMENT_REMINDER", 45) # Seconds before sending reminder message
|
ASSIGNMENT_REMINDER = get_config("ASSIGNMENT_REMINDER", 45, is_int=True) # Seconds before sending reminder message
|
||||||
|
|
||||||
# Chain Timer Settings
|
# 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
|
# Authentication
|
||||||
AUTH_PASSWORD = _config.get("AUTH_PASSWORD", "YOUR_AUTH_PASSWORD_HERE") # Universal password for all users
|
AUTH_PASSWORD = get_config("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
|
JWT_SECRET = get_config("JWT_SECRET", "your-secret-key-change-this") # Secret key for JWT tokens
|
||||||
|
|||||||
30
faction-war.service
Normal file
30
faction-war.service
Normal file
@@ -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
|
||||||
58
nginx.conf.example
Normal file
58
nginx.conf.example
Normal file
@@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
8
requirements.txt
Normal file
8
requirements.txt
Normal file
@@ -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
|
||||||
162
setup_production.sh
Normal file
162
setup_production.sh
Normal file
@@ -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 ""
|
||||||
Reference in New Issue
Block a user