# 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.