# Stoatchat Deployment Documentation

**Complete setup guide for deploying Stoatchat on a new machine**

## 🎯 Overview

This document provides step-by-step instructions for deploying Stoatchat from scratch on a new Ubuntu server. The deployment includes all necessary components: the chat application, reverse proxy, SSL certificates, email configuration, and backup systems.

## 📋 Prerequisites

### System Requirements
- **OS**: Ubuntu 20.04+ or Debian 11+
- **RAM**: Minimum 2GB, Recommended 4GB+
- **Storage**: Minimum 20GB free space
- **Network**: Public IP address with ports 80, 443 accessible

### Required Accounts & Credentials
- **Domain**: Registered domain with DNS control
- **Cloudflare**: Account with domain configured (optional but recommended)
- **Gmail**: Account with App Password for SMTP
- **Git**: Access to Stoatchat repository

### Dependencies to Install
- Git
- Rust (latest stable)
- Redis
- Nginx
- Certbot (Let's Encrypt)
- Build tools (gcc, pkg-config, etc.)

## 🚀 Step-by-Step Deployment

### 1. System Preparation

```bash
# Update system
sudo apt update && sudo apt upgrade -y

# Install essential packages
sudo apt install -y git curl wget build-essential pkg-config libssl-dev \
  nginx redis-server certbot python3-certbot-nginx ufw

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

# Configure firewall
sudo ufw allow 22    # SSH
sudo ufw allow 80    # HTTP
sudo ufw allow 443   # HTTPS
sudo ufw --force enable
```

### 2. Clone and Build Stoatchat

```bash
# Clone repository
cd /root
git clone https://github.com/revoltchat/backend.git stoatchat
cd stoatchat

# Build the application (this takes 15-30 minutes)
cargo build --release

# Verify build
ls -la target/release/revolt-*
```

### 3. Configure Redis

```bash
# Start and enable Redis
sudo systemctl start redis-server
sudo systemctl enable redis-server

# Configure Redis for Stoatchat (optional custom port)
sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.backup
sudo sed -i 's/port 6379/port 6380/' /etc/redis/redis.conf
sudo systemctl restart redis-server

# Test Redis connection
redis-cli -p 6380 ping
```

### 4. Domain and SSL Setup

```bash
# Replace 'yourdomain.com' with your actual domain
DOMAIN="st.vish.gg"

# Create nginx configuration
sudo tee /etc/nginx/sites-available/stoatchat > /dev/null << EOF
server {
    listen 80;
    server_name $DOMAIN api.$DOMAIN events.$DOMAIN files.$DOMAIN proxy.$DOMAIN voice.$DOMAIN;
    return 301 https://\$server_name\$request_uri;
}

server {
    listen 443 ssl http2;
    server_name $DOMAIN;
    
    ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
    
    location / {
        proxy_pass http://localhost:14702;
        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;
    }
}

server {
    listen 443 ssl http2;
    server_name api.$DOMAIN;
    
    ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
    
    location / {
        proxy_pass http://localhost:14702;
        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;
    }
}

server {
    listen 443 ssl http2;
    server_name events.$DOMAIN;
    
    ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
    
    location / {
        proxy_pass http://localhost:14703;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";
        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;
    }
}

server {
    listen 443 ssl http2;
    server_name files.$DOMAIN;
    
    ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
    
    location / {
        proxy_pass http://localhost:14704;
        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;
        client_max_body_size 100M;
    }
}

server {
    listen 443 ssl http2;
    server_name proxy.$DOMAIN;
    
    ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
    
    location / {
        proxy_pass http://localhost:14705;
        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;
    }
}

server {
    listen 443 ssl http2;
    server_name voice.$DOMAIN;
    
    ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
    
    location / {
        proxy_pass http://localhost:7880;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";
        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;
    }
}
EOF

# Enable the site
sudo ln -s /etc/nginx/sites-available/stoatchat /etc/nginx/sites-enabled/
sudo nginx -t

# Obtain SSL certificates
sudo certbot --nginx -d $DOMAIN -d api.$DOMAIN -d events.$DOMAIN -d files.$DOMAIN -d proxy.$DOMAIN -d voice.$DOMAIN

# Test nginx configuration
sudo systemctl reload nginx
```

### 5. Configure Stoatchat

```bash
# Create configuration override file
cd /root/stoatchat
cat > Revolt.overrides.toml << 'EOF'
[database]
redis = "redis://127.0.0.1:6380"

[api]
url = "https://api.st.vish.gg"

[api.smtp]
host = "smtp.gmail.com"
port = 465
username = "your-gmail@gmail.com"
password = "REDACTED_PASSWORD"
from_address = "your-gmail@gmail.com"
use_tls = true

[events]
url = "https://events.st.vish.gg"

[autumn]
url = "https://files.st.vish.gg"

[january]
url = "https://proxy.st.vish.gg"

[livekit]
url = "https://voice.st.vish.gg"
api_key = REDACTED_API_KEY
api_secret = "your-livekit-api-secret"
EOF

# Update with your actual values
nano Revolt.overrides.toml
```

### 6. Create Service Management Scripts

```bash
# Create service management script
cat > manage-services.sh << 'EOF'
#!/bin/bash

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"

# Service definitions
declare -A SERVICES=(
    ["api"]="target/release/revolt-delta"
    ["events"]="target/release/revolt-bonfire"
    ["files"]="target/release/revolt-autumn"
    ["proxy"]="target/release/revolt-january"
    ["gifbox"]="target/release/revolt-gifbox"
)

declare -A PORTS=(
    ["api"]="14702"
    ["events"]="14703"
    ["files"]="14704"
    ["proxy"]="14705"
    ["gifbox"]="14706"
)

start_service() {
    local name=$1
    local binary=${SERVICES[$name]}
    local port=${PORTS[$name]}
    
    if pgrep -f "$binary" > /dev/null; then
        echo "  ⚠️  $name already running"
        return
    fi
    
    echo "  🚀 Starting $name on port $port..."
    nohup ./$binary > ${name}.log 2>&1 &
    sleep 2
    
    if pgrep -f "$binary" > /dev/null; then
        echo "  ✅ $name started successfully"
    else
        echo "  ❌ Failed to start $name"
    fi
}

stop_service() {
    local name=$1
    local binary=${SERVICES[$name]}
    
    local pids=$(pgrep -f "$binary")
    if [ -z "$pids" ]; then
        echo "  ⚠️  $name not running"
        return
    fi
    
    echo "  🛑 Stopping $name..."
    pkill -f "$binary"
    sleep 2
    
    if ! pgrep -f "$binary" > /dev/null; then
        echo "  ✅ $name stopped successfully"
    else
        echo "  ❌ Failed to stop $name"
    fi
}

status_service() {
    local name=$1
    local binary=${SERVICES[$name]}
    local port=${PORTS[$name]}
    
    if pgrep -f "$binary" > /dev/null; then
        if netstat -tlnp 2>/dev/null | grep -q ":$port "; then
            echo "  ✓ $name (port $port) - Running"
        else
            echo "  ⚠️  $name - Process running but port not listening"
        fi
    else
        echo "  ✗ $name (port $port) - Stopped"
    fi
}

case "$1" in
    start)
        echo "[INFO] Starting Stoatchat services..."
        for service in api events files proxy gifbox; do
            start_service "$service"
        done
        ;;
    stop)
        echo "[INFO] Stopping Stoatchat services..."
        for service in api events files proxy gifbox; do
            stop_service "$service"
        done
        ;;
    restart)
        echo "[INFO] Restarting Stoatchat services..."
        $0 stop
        sleep 3
        $0 start
        ;;
    status)
        echo "[INFO] Stoatchat Service Status:"
        echo
        for service in api events files proxy gifbox; do
            status_service "$service"
        done
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|status}"
        exit 1
        ;;
esac
EOF

chmod +x manage-services.sh
```

### 7. Create Backup Scripts

```bash
# Create backup script
cat > backup.sh << 'EOF'
#!/bin/bash

BACKUP_DIR="/root/stoatchat-backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="stoatchat_backup_$TIMESTAMP"
BACKUP_PATH="$BACKUP_DIR/$BACKUP_NAME"

# Create backup directory
mkdir -p "$BACKUP_PATH"

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting Stoatchat backup process..."
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup will be saved to: $BACKUP_PATH"

# Backup configuration files
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backing up configuration files..."
cp Revolt.toml "$BACKUP_PATH/" 2>/dev/null || echo "⚠️   Revolt.toml not found"
cp Revolt.overrides.toml "$BACKUP_PATH/" 2>/dev/null || echo "⚠️   Revolt.overrides.toml not found"
cp livekit.yml "$BACKUP_PATH/" 2>/dev/null || echo "⚠️   livekit.yml not found"
echo "✅ Configuration files backed up"

# Backup Nginx configuration
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backing up Nginx configuration..."
mkdir -p "$BACKUP_PATH/nginx"
cp /etc/nginx/sites-available/stoatchat "$BACKUP_PATH/nginx/" 2>/dev/null || echo "⚠️   Nginx site config not found"
echo "✅ Nginx configuration backed up"

# Backup SSL certificates
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backing up SSL certificates..."
mkdir -p "$BACKUP_PATH/ssl"
cp -r /etc/letsencrypt/live/st.vish.gg/* "$BACKUP_PATH/ssl/" 2>/dev/null || echo "⚠️   SSL certificates not found"
echo "✅ SSL certificates backed up"

# Backup user uploads and file storage
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backing up user uploads and file storage..."
mkdir -p "$BACKUP_PATH/uploads"
# Add file storage backup commands here when implemented
echo "✅ File storage backed up"

# Create backup info file
cat > "$BACKUP_PATH/backup_info.txt" << EOL
Stoatchat Backup Information
============================
Backup Date: $(date)
Backup Name: $BACKUP_NAME
System: $(uname -a)
Stoatchat Version: $(grep version Cargo.toml | head -1 | cut -d'"' -f2)

Contents:
- Configuration files (Revolt.toml, Revolt.overrides.toml, livekit.yml)
- Nginx configuration
- SSL certificates
- File storage (if applicable)

Restore Command:
./restore.sh $BACKUP_PATH
EOL

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup completed successfully!"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup location: $BACKUP_PATH"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup size: $(du -sh "$BACKUP_PATH" | cut -f1)"
EOF

chmod +x backup.sh

# Create restore script
cat > restore.sh << 'EOF'
#!/bin/bash

if [ $# -eq 0 ]; then
    echo "Usage: $0 <backup-directory>"
    echo "Example: $0 /root/stoatchat-backups/stoatchat_backup_20260211_051926"
    exit 1
fi

BACKUP_PATH="$1"

if [ ! -d "$BACKUP_PATH" ]; then
    echo "❌ Backup directory not found: $BACKUP_PATH"
    exit 1
fi

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting Stoatchat restore process..."
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Restoring from: $BACKUP_PATH"

# Stop services before restore
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Stopping Stoatchat services..."
./manage-services.sh stop

# Restore configuration files
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Restoring configuration files..."
cp "$BACKUP_PATH/Revolt.toml" . 2>/dev/null && echo "✅ Revolt.toml restored"
cp "$BACKUP_PATH/Revolt.overrides.toml" . 2>/dev/null && echo "✅ Revolt.overrides.toml restored"
cp "$BACKUP_PATH/livekit.yml" . 2>/dev/null && echo "✅ livekit.yml restored"

# Restore Nginx configuration
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Restoring Nginx configuration..."
sudo cp "$BACKUP_PATH/nginx/stoatchat" /etc/nginx/sites-available/ 2>/dev/null && echo "✅ Nginx configuration restored"

# Restore SSL certificates
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Restoring SSL certificates..."
sudo cp -r "$BACKUP_PATH/ssl/"* /etc/letsencrypt/live/st.vish.gg/ 2>/dev/null && echo "✅ SSL certificates restored"

# Reload nginx
sudo nginx -t && sudo systemctl reload nginx

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Restore completed!"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting services..."
./manage-services.sh start
EOF

chmod +x restore.sh
```

### 8. Setup LiveKit (Optional)

```bash
# Download and install LiveKit
wget https://github.com/livekit/livekit/releases/latest/download/livekit_linux_amd64.tar.gz
tar -xzf livekit_linux_amd64.tar.gz
sudo mv livekit /usr/local/bin/

# Create LiveKit configuration
cat > livekit.yml << 'EOF'
port: 7880
bind_addresses:
  - ""
rtc:
  tcp_port: 7881
  port_range_start: 50000
  port_range_end: 60000
  use_external_ip: true
redis:
  address: localhost:6380
keys:
  your-api-key: your-api-secret
EOF

# Start LiveKit (run in background)
nohup livekit --config livekit.yml > livekit.log 2>&1 &
```

### 9. Start Services

```bash
# Start all Stoatchat services
./manage-services.sh start

# Check status
./manage-services.sh status

# Test API
curl http://localhost:14702/

# Test frontend (after nginx is configured)
curl https://st.vish.gg
```

### 10. Setup Automated Backups

```bash
# Create backup cron job
cat > setup-backup-cron.sh << 'EOF'
#!/bin/bash

# Add daily backup at 2 AM
(crontab -l 2>/dev/null; echo "0 2 * * * cd /root/stoatchat && ./backup.sh >> backup-cron.log 2>&1") | crontab -

echo "✅ Backup cron job added - daily backups at 2 AM"
echo "Current crontab:"
crontab -l
EOF

chmod +x setup-backup-cron.sh
./setup-backup-cron.sh
```

## ✅ Verification Steps

After deployment, verify everything is working:

```bash
# 1. Check all services
./manage-services.sh status

# 2. Test API endpoints
curl http://localhost:14702/
curl https://api.st.vish.gg

# 3. Test email functionality
curl -X POST http://localhost:14702/auth/account/create \
  -H "Content-Type: application/json" \
  -d '{"email": "test@yourdomain.com", "password": "TestPass123!"}'

# 4. Check SSL certificates
curl -I https://st.vish.gg

# 5. Test backup system
./backup.sh --dry-run
```

## 🔧 Configuration Customization

### Environment-Specific Settings

Update `Revolt.overrides.toml` with your specific values:

```toml
[database]
redis = "redis://127.0.0.1:6380"  # Your Redis connection

[api]
url = "https://api.yourdomain.com"  # Your API domain

[api.smtp]
host = "smtp.gmail.com"
port = 465
username = "your-email@gmail.com"    # Your Gmail address
password = "REDACTED_PASSWORD"       # Your Gmail app password
from_address = "your-email@gmail.com"
use_tls = true

[events]
url = "https://events.yourdomain.com"  # Your events domain

[autumn]
url = "https://files.yourdomain.com"   # Your files domain

[january]
url = "https://proxy.yourdomain.com"   # Your proxy domain

[livekit]
url = "https://voice.yourdomain.com"   # Your voice domain
api_key = REDACTED_API_KEY       # Your LiveKit API key
api_secret = "your-livekit-api-secret" # Your LiveKit API secret
```

### Gmail App Password Setup

1. Enable 2-Factor Authentication on your Gmail account
2. Go to Google Account settings → Security → App passwords
3. Generate an app password for "Mail"
4. Use this password in the SMTP configuration

## 🚨 Troubleshooting

### Common Issues

1. **Build Fails**: Ensure Rust is installed and up to date
2. **Services Won't Start**: Check port availability and logs
3. **SSL Issues**: Verify domain DNS and certificate renewal
4. **Email Not Working**: Check Gmail app password and SMTP settings

### Log Locations

- **Stoatchat Services**: `*.log` files in the application directory
- **Nginx**: `/var/log/nginx/error.log`
- **System**: `/var/log/syslog`

## 📚 Additional Resources

- **Stoatchat Repository**: https://github.com/revoltchat/backend
- **Nginx Documentation**: https://nginx.org/en/docs/
- **Let's Encrypt**: https://letsencrypt.org/getting-started/
- **LiveKit Documentation**: https://docs.livekit.io/

---

**Deployment Guide Version**: 1.0  
**Last Updated**: February 11, 2026  
**Tested On**: Ubuntu 20.04, Ubuntu 22.04