# Stoatchat Complete Deployment Guide - Seattle VM

This guide documents the complete process used to deploy Stoatchat on the Seattle VM. Follow these steps to recreate the deployment on a new server.

## Prerequisites

- Ubuntu/Debian server with root access
- Domain name with Cloudflare DNS management
- Gmail account with App Password for SMTP
- At least 4GB RAM and 20GB storage

## Step 1: Server Preparation

### 1.1 Update System
```bash
apt update && apt upgrade -y
apt install -y curl wget git build-essential pkg-config libssl-dev nginx certbot python3-certbot-nginx
```

### 1.2 Install Docker
```bash
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
systemctl enable docker
systemctl start docker
```

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

## Step 2: Clone and Build Stoatchat

### 2.1 Clone Repository
```bash
cd /root
git clone https://github.com/stoatchat/stoatchat.git
cd stoatchat
```

### 2.2 Build Services
```bash
# This takes 15-30 minutes depending on server specs
cargo build --release

# Or for debug builds (faster compilation, used in current deployment):
cargo build
```

## Step 3: Infrastructure Services Setup

### 3.1 Create Docker Compose File
```bash
cat > compose.yml << 'EOF'
services:
  redis:
    image: eqalpha/keydb
    container_name: stoatchat-redis
    ports:
      - "6380:6379"
    volumes:
      - ./data/redis:/data
    restart: unless-stopped

  database:
    image: mongo:7
    container_name: stoatchat-mongodb
    ports:
      - "27017:27017"
    volumes:
      - ./data/mongodb:/data/db
    environment:
      MONGO_INITDB_ROOT_USERNAME: stoatchat
      MONGO_INITDB_ROOT_PASSWORD: "REDACTED_PASSWORD"
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    restart: unless-stopped

  minio:
    image: minio/minio:latest
    container_name: stoatchat-minio
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: REDACTED_MINIO_CRED
      MINIO_ROOT_PASSWORD: "REDACTED_PASSWORD"
    volumes:
      - ./data/minio:/data
    ports:
      - "14009:9000"
      - "9001:9001"
    restart: unless-stopped

  livekit:
    image: livekit/livekit-server:v1.9.9
    container_name: stoatchat-livekit
    ports:
      - "7880:7880"
      - "7881:7881"
      - "7882:7882/udp"
    volumes:
      - ./livekit.yml:/livekit.yml:ro
    command: --config /livekit.yml
    restart: unless-stopped
EOF
```

### 3.2 Create LiveKit Configuration
```bash
cat > livekit.yml << 'EOF'
port: 7880
redis:
    address: localhost:6380
    username: ""
    password: ""
webhook:
  api_key: worldwide
  urls:
    - 'http://localhost:8500/worldwide'
logging:
  level: debug
keys:
  worldwide: YOUR_LIVEKIT_API_KEY_GENERATE_RANDOM_32_CHARS
EOF
```

### 3.3 Start Infrastructure Services
```bash
docker-compose up -d
```

## Step 4: Stoatchat Configuration

### 4.1 Create Configuration Override
```bash
cat > Revolt.overrides.toml << 'EOF'
[database]
redis = "redis://127.0.0.1:6380/"
mongodb = "mongodb://stoatchat:YOUR_SECURE_MONGODB_PASSWORD@127.0.0.1:27017/revolt"

[hosts]
app = "https://YOUR_DOMAIN"
api = "https://api.YOUR_DOMAIN"
events = "wss://events.YOUR_DOMAIN"
autumn = "https://files.YOUR_DOMAIN"
january = "https://proxy.YOUR_DOMAIN"

[hosts.livekit]
worldwide = "wss://voice.YOUR_DOMAIN"

[email]
smtp_host = "smtp.gmail.com"
smtp_port = 587
smtp_username = "YOUR_GMAIL@gmail.com"
smtp_password = "REDACTED_PASSWORD"
from_address = "YOUR_GMAIL@gmail.com"
smtp_tls = true

[files]
s3_region = "us-east-1"
s3_bucket = "revolt-uploads"
s3_endpoint = "http://127.0.0.1:14009"
s3_access_key_id = "REDACTED_MINIO_CRED"
s3_secret_access_key = "YOUR_SECURE_MINIO_PASSWORD"

[security]
vapid_private_key = REDACTED_VAPID_PRIVATE_KEY

[features]
captcha_enabled = false
email_verification = true
invite_only = false

[limits]
max_file_size = 104857600  # 100MB
max_message_length = 2000
max_embed_count = 10
EOF
```

## Step 5: SSL Certificates Setup

### 5.1 Configure Cloudflare DNS
Set up A records for all subdomains pointing to your server IP:
- YOUR_DOMAIN
- api.YOUR_DOMAIN
- events.YOUR_DOMAIN
- files.YOUR_DOMAIN
- proxy.YOUR_DOMAIN
- voice.YOUR_DOMAIN

### 5.2 Obtain SSL Certificates
```bash
# Get certificates for all domains
certbot certonly --nginx -d YOUR_DOMAIN -d api.YOUR_DOMAIN -d events.YOUR_DOMAIN -d files.YOUR_DOMAIN -d proxy.YOUR_DOMAIN -d voice.YOUR_DOMAIN

# Or individually if needed:
certbot certonly --nginx -d YOUR_DOMAIN
certbot certonly --nginx -d api.YOUR_DOMAIN
certbot certonly --nginx -d events.YOUR_DOMAIN
certbot certonly --nginx -d files.YOUR_DOMAIN
certbot certonly --nginx -d proxy.YOUR_DOMAIN
certbot certonly --nginx -d voice.YOUR_DOMAIN
```

## Step 6: Nginx Configuration

### 6.1 Create Nginx Configuration
```bash
cat > /etc/nginx/sites-available/stoatchat << 'EOF'
# Main app (placeholder/frontend)
server {
    listen 80;
    server_name YOUR_DOMAIN;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name YOUR_DOMAIN;
    
    ssl_certificate /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem;
    
    location / {
        return 200 'Stoatchat - Coming Soon';
        add_header Content-Type text/plain;
    }
}

# API Server
server {
    listen 80;
    server_name api.YOUR_DOMAIN;
    return 301 https://$server_name$request_uri;
}

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

# Events WebSocket
server {
    listen 80;
    server_name events.YOUR_DOMAIN;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name events.YOUR_DOMAIN;
    
    ssl_certificate /etc/letsencrypt/live/events.YOUR_DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/events.YOUR_DOMAIN/privkey.pem;
    
    location / {
        proxy_pass http://127.0.0.1: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;
        proxy_read_timeout 86400;
    }
}

# File Server
server {
    listen 80;
    server_name files.YOUR_DOMAIN;
    return 301 https://$server_name$request_uri;
}

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

# Media Proxy
server {
    listen 80;
    server_name proxy.YOUR_DOMAIN;
    return 301 https://$server_name$request_uri;
}

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

# Voice/Video (LiveKit)
server {
    listen 80;
    server_name voice.YOUR_DOMAIN;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name voice.YOUR_DOMAIN;
    
    ssl_certificate /etc/letsencrypt/live/voice.YOUR_DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/voice.YOUR_DOMAIN/privkey.pem;
    
    location / {
        proxy_pass http://127.0.0.1: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;
        proxy_read_timeout 86400;
    }
}
EOF
```

### 6.2 Enable Configuration
```bash
ln -s /etc/nginx/sites-available/stoatchat /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx
```

## Step 7: Start Stoatchat Services

### 7.1 Create Service Startup Script
```bash
cat > /root/stoatchat/start-services.sh << 'EOF'
#!/bin/bash
cd /root/stoatchat

# Start services in background
nohup ./target/debug/revolt-delta > api.log 2>&1 &
nohup ./target/debug/revolt-bonfire > events.log 2>&1 &
nohup ./target/debug/revolt-autumn > files.log 2>&1 &
nohup ./target/debug/revolt-january > proxy.log 2>&1 &
nohup ./target/debug/revolt-gifbox > gifbox.log 2>&1 &

echo "All Stoatchat services started"
EOF

chmod +x /root/stoatchat/start-services.sh
```

### 7.2 Start Services
```bash
cd /root/stoatchat
./start-services.sh
```

## Step 8: Verification

### 8.1 Check Services
```bash
# Check processes
ps aux | grep revolt

# Check ports
ss -tlnp | grep -E "(14702|14703|14704|14705|14706|7880)"

# Test endpoints
curl -k https://api.YOUR_DOMAIN/
curl -k https://files.YOUR_DOMAIN/
curl -k https://proxy.YOUR_DOMAIN/
curl -k https://voice.YOUR_DOMAIN/
```

### 8.2 Expected Responses
- API: `{"revolt":"0.10.3","features":...}`
- Files: `{"autumn":"Hello, I am a file server!","version":"0.10.3"}`
- Proxy: `{"january":"Hello, I am a media proxy server!","version":"0.10.3"}`
- Voice: `OK`

## Step 9: Setup Systemd Services (Optional but Recommended)

### 9.1 Create Systemd Service Files
```bash
# Create service for each component
cat > /etc/systemd/system/stoatchat-api.service << 'EOF'
[Unit]
Description=Stoatchat API Server
After=network.target docker.service
Requires=docker.service

[Service]
Type=simple
User=root
WorkingDirectory=/root/stoatchat
ExecStart=/root/stoatchat/target/debug/revolt-delta
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

# Repeat for other services...
systemctl daemon-reload
systemctl enable stoatchat-api
systemctl start stoatchat-api
```

## Step 10: Frontend Setup (Future)

The main domain currently shows a placeholder. To complete the setup:

1. Deploy a Revolt.js frontend or compatible client
2. Update nginx configuration to serve the frontend
3. Configure the frontend to use your API endpoints

## Security Considerations

1. **Change all default passwords** in the configuration files
2. **Generate new API keys** for LiveKit and VAPID
3. **Set up firewall rules** to restrict access to internal ports
4. **Enable fail2ban** for SSH protection
5. **Regular security updates** for the system and Docker images

## Backup Strategy

1. **Database**: Regular MongoDB dumps
2. **Files**: Backup MinIO data directory
3. **Configuration**: Backup all .toml and .yml files
4. **SSL Certificates**: Backup Let's Encrypt directory

## Monitoring

Consider setting up monitoring for:
- Service health checks
- Resource usage (CPU, RAM, disk)
- Log aggregation
- SSL certificate expiration
- Database performance

---

This deployment guide captures the complete process used to set up Stoatchat on the Seattle VM. Adjust domain names, passwords, and paths as needed for your specific deployment.