# Cloud Deployment Guide Deploy the Remote Coding Agent to a cloud VPS for 24/7 operation with automatic HTTPS and persistent uptime. **Navigation:** [Prerequisites](#prerequisites) • [Server Setup](#1-server-provisioning--initial-setup) • [DNS Configuration](#2-dns-configuration) • [Repository Setup](#3-clone-repository) • [Environment Config](#4-environment-configuration) • [Database Migration](#5-database-migration) • [Caddy Setup](#6-caddy-configuration) • [Start Services](#7-start-services) • [Verify](#8-verify-deployment) --- ## Prerequisites **Required:** - Cloud VPS account (DigitalOcean, Linode, AWS EC2, Vultr, etc.) - Domain name or subdomain (e.g., `remote-agent.yourdomain.com`) - SSH client installed on your local machine - Basic command-line familiarity **Recommended Specs:** - **CPU:** 1-2 vCPUs - **RAM:** 2GB minimum (4GB recommended) - **Storage:** 20GB SSD - **OS:** Ubuntu 22.04 LTS ### Generate SSH Key (Required) **Before creating your VPS**, generate an SSH key pair on your local machine: ```bash # Generate SSH key (ed25519 recommended) ssh-keygen -t ed25519 -C "remote-coding-agent" # When prompted: # - File location: Press Enter (uses default ~/.ssh/id_ed25519) # - Passphrase: Optional but recommended # View your public key (you'll need this for VPS setup) cat ~/.ssh/id_ed25519.pub # Windows: type %USERPROFILE%\.ssh\id_ed25519.pub ``` **Copy the public key output** - you'll add this to your VPS during creation. --- ## 1. Server Provisioning & Initial Setup ### Create VPS Instance (Examples)
DigitalOcean Droplet 1. Log in to [DigitalOcean](https://www.digitalocean.com/) 2. Click "Create" → "Droplets" 3. Choose: - **Image:** Ubuntu 22.04 LTS - **Plan:** Basic ($12/month - 2GB RAM recommended) - **Datacenter:** Choose closest to your users - **Authentication:** SSH keys → "New SSH Key" → Paste your public key from Prerequisites 4. Click "Create Droplet" 5. Note the public IP address
AWS EC2 Instance 1. Log in to [AWS Console](https://console.aws.amazon.com/) 2. Navigate to EC2 → Launch Instance 3. Choose: - **AMI:** Ubuntu Server 22.04 LTS - **Instance Type:** t3.small (2GB RAM) - **Key Pair:** "Create new key pair" or import your public key from Prerequisites - **Security Group:** Allow SSH (22), HTTP (80), HTTPS (443) 4. Launch instance 5. Note the public IP address
Linode Instance 1. Log in to [Linode](https://www.linode.com/) 2. Click "Create" → "Linode" 3. Choose: - **Image:** Ubuntu 22.04 LTS - **Region:** Choose closest to your users - **Plan:** Nanode 2GB ($12/month) - **SSH Keys:** Add your public key from Prerequisites - **Root Password:** Set strong password (backup access) 4. Click "Create Linode" 5. Note the public IP address
### Initial Server Configuration **Connect to your server:** ```bash # Replace with your server IP (uses SSH key from Prerequisites) ssh -i ~/.ssh/id_ed25519 root@your-server-ip ``` **Create deployment user:** ```bash # Create user with sudo privileges adduser deploy usermod -aG sudo deploy # Copy root's SSH authorized keys to deploy user mkdir -p /home/deploy/.ssh cp /root/.ssh/authorized_keys /home/deploy/.ssh/ chown -R deploy:deploy /home/deploy/.ssh chmod 700 /home/deploy/.ssh chmod 600 /home/deploy/.ssh/authorized_keys # Test connection in a new terminal before proceeding: # ssh -i ~/.ssh/id_ed25519 deploy@your-server-ip ``` **Disable password authentication for security:** ```bash # Edit SSH config nano /etc/ssh/sshd_config ``` Find and change: ``` PasswordAuthentication no ``` > To get out of Nano after making changes, press: Ctrl + X -> Y -> enter Restart SSH: ```bash systemctl restart ssh # Switch to deploy user for remaining steps su - deploy ``` **Configure firewall:** ```bash # Allow SSH, HTTP, HTTPS (including HTTP/3) sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443 # Enable firewall sudo ufw --force enable # Check status sudo ufw status ``` ### Install Dependencies **Install Docker:** ```bash # Install Docker curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh # Add deploy user to docker group sudo usermod -aG docker deploy # Log out and back in for group changes to take effect exit ssh -i ~/.ssh/id_ed25519 deploy@your-server-ip ``` **Install Docker Compose, Git, and PostgreSQL Client:** ```bash # Update package list sudo apt update # Install required packages sudo apt install -y docker-compose-plugin git postgresql-client # Verify installations docker --version docker compose version git --version psql --version ``` --- ## 2. DNS Configuration Point your domain to your server's IP address. **A Record Setup:** 1. Go to your domain registrar or DNS provider (Cloudflare, Namecheap, etc.) 2. Create an **A Record**: - **Name:** `remote-agent` (for `remote-agent.yourdomain.com`) or `@` (for `yourdomain.com`) - **Value:** Your server's public IP address - **TTL:** 300 (5 minutes) or default **Example (Cloudflare):** ``` Type: A Name: remote-agent Content: 123.45.67.89 Proxy: Off (DNS Only) TTL: Auto ``` --- ## 3. Clone Repository **On your server:** ```bash # Create application directory sudo mkdir -p /remote-coding-agent sudo chown deploy:deploy /remote-coding-agent # Clone repository into the directory cd /remote-coding-agent git clone https://github.com/dynamous-community/remote-coding-agent . ``` --- ## 4. Environment Configuration ### Create Environment File ```bash # Copy example file cp .env.example .env # Edit with nano nano .env ``` ### 4.1 Core Configuration Set these required variables: ```env # Database - Use remote managed PostgreSQL DATABASE_URL=postgresql://user:password@host:5432/dbname # GitHub tokens (same value for both) GH_TOKEN=ghp_your_token_here GITHUB_TOKEN=ghp_your_token_here # Server settings PORT=3090 ARCHON_HOME=/tmp/archon # Override base directory (optional) ``` **GitHub Token Setup:** 1. Visit [GitHub Settings > Tokens](https://github.com/settings/tokens) 2. Click "Generate new token (classic)" 3. Select scope: **`repo`** 4. Copy token (starts with `ghp_...`) 5. Set both `GH_TOKEN` and `GITHUB_TOKEN` in `.env` **Database Options:**
Recommended: Remote Managed PostgreSQL Use a managed database service for easier backups and scaling. **Supabase (Free tier available):** 1. Create project at [supabase.com](https://supabase.com) 2. Go to Settings → Database 3. Copy connection string (Transaction pooler recommended) 4. Set as `DATABASE_URL` **Neon:** 1. Create project at [neon.tech](https://neon.tech) 2. Copy connection string from dashboard 3. Set as `DATABASE_URL`
Alternative: Local PostgreSQL (with-db profile) To run PostgreSQL in Docker alongside the app: ```env DATABASE_URL=postgresql://postgres:postgres@postgres:5432/remote_coding_agent ``` Use the `with-db` profile when starting services (see Section 6).
**For detailed database setup, see [Core Configuration](../README.md#1-core-configuration-required) in the main README.** ### 4.2 AI Assistant Setup **Configure at least one AI assistant.**
🤖 Claude Code **On your local machine:** ```bash # Install Claude Code CLI (if not already installed) # Visit: https://docs.claude.com/claude-code/installation # Generate OAuth token claude setup-token # Copy the token (starts with sk-ant-oat01-...) ``` **On your server:** ```bash nano .env ``` Add: ```env CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-xxxxx ``` **Alternative: API Key** If you prefer pay-per-use: 1. Visit [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys) 2. Create key (starts with `sk-ant-`) 3. Set in `.env`: ```env CLAUDE_API_KEY=sk-ant-xxxxx ``` **Set as default (optional):** ```env DEFAULT_AI_ASSISTANT=claude ``` **For detailed Claude setup, see [AI Assistant Setup](../README.md#2-ai-assistant-setup-choose-at-least-one).**
🤖 Codex **On your local machine:** ```bash # Install Codex CLI (if not already installed) # Visit: https://docs.codex.com/installation # Authenticate codex login # Extract credentials cat ~/.codex/auth.json # On Windows: type %USERPROFILE%\.codex\auth.json # Copy all four values ``` **On your server:** ```bash nano .env ``` Add all four credentials: ```env CODEX_ID_TOKEN=eyJhbGc... CODEX_ACCESS_TOKEN=eyJhbGc... CODEX_REFRESH_TOKEN=rt_... CODEX_ACCOUNT_ID=6a6a7ba6-... ``` **Set as default (optional):** ```env DEFAULT_AI_ASSISTANT=codex ``` **For detailed Codex setup, see [AI Assistant Setup](../README.md#2-ai-assistant-setup-choose-at-least-one).**
### 4.3 Platform Adapter Setup **Configure at least one platform.**
💬 Telegram **Create bot:** 1. Message [@BotFather](https://t.me/BotFather) on Telegram 2. Send `/newbot` and follow prompts 3. Copy bot token (format: `123456789:ABCdefGHIjklMNOpqrsTUVwxyz`) **On your server:** ```bash nano .env ``` Add: ```env TELEGRAM_BOT_TOKEN=123456789:ABCdefGHI... TELEGRAM_STREAMING_MODE=stream # stream (default) | batch ``` **For detailed Telegram setup, see [Platform Setup](../README.md#3-platform-adapter-setup-choose-at-least-one).**
🐙 GitHub Webhooks **You'll configure this AFTER deployment** (need public URL first). For now, just generate the webhook secret: ```bash # Generate secret openssl rand -hex 32 # Copy the output ``` Add to `.env`: ```env WEBHOOK_SECRET=your_generated_secret_here GITHUB_STREAMING_MODE=batch # batch (default) | stream ``` **GitHub webhook configuration happens in Section 9 after services are running.**
**Save and exit nano:** `Ctrl+X`, then `Y`, then `Enter` --- ## 5. Database Migration **IMPORTANT: Run this BEFORE starting the application.** Initialize the database schema with required tables: ```bash # For remote database (Supabase, Neon, etc.) psql $DATABASE_URL < migrations/001_initial_schema.sql # Verify tables were created psql $DATABASE_URL -c "\dt" # Should show: conversations, codebases, sessions ``` **If using local PostgreSQL with `with-db` profile:** You'll run migrations after starting the database in Section 7. --- ## 6. Caddy Configuration Caddy provides automatic HTTPS with Let's Encrypt certificates. ### Create Caddyfile ```bash # Copy example file cp Caddyfile.example Caddyfile # Edit with your domain nano Caddyfile ``` **Update with your domain:** ``` remote-agent.yourdomain.com { reverse_proxy app:3090 } ``` Replace `remote-agent.yourdomain.com` with your actual domain. > **Note:** If using `with-db` profile (local PostgreSQL), change `app:3090` to `app-with-db:3090` **Save and exit:** `Ctrl+X`, then `Y`, then `Enter` ### How Caddy Works - Automatically obtains SSL certificates from Let's Encrypt - Handles HTTPS (443) and HTTP (80) → HTTPS redirect - Proxies requests to app container on port 3090 - Renews certificates automatically --- ## 7. Start Services ### Setup Workspace Permissions (Linux Only) ```bash # Create workspace directory and set permissions for container user (UID 1001) mkdir -p workspace sudo chown -R 1001:1001 workspace ``` ### Option A: With Remote PostgreSQL (Recommended) If using managed database: ```bash # Start app with Caddy reverse proxy docker compose --profile external-db -f docker-compose.yml -f docker-compose.cloud.yml up -d --build # View logs docker compose --profile external-db -f docker-compose.yml -f docker-compose.cloud.yml logs -f app ``` ### Option B: With Local PostgreSQL If using `with-db` profile: ```bash # Start app, postgres, and Caddy docker compose --profile with-db -f docker-compose.yml -f docker-compose.cloud.yml up -d --build # View logs docker compose --profile with-db -f docker-compose.yml -f docker-compose.cloud.yml logs -f app docker compose --profile with-db -f docker-compose.yml -f docker-compose.cloud.yml logs -f postgres ``` ### Monitor Startup ```bash # Watch logs for successful startup (use --profile with-db for local PostgreSQL) docker compose --profile external-db -f docker-compose.yml -f docker-compose.cloud.yml logs -f app # Look for: # [App] Starting Remote Coding Agent # [Database] Connected successfully # [App] Remote Coding Agent is ready! ``` **Press `Ctrl+C` to exit logs (services keep running).** --- ## 8. Verify Deployment ### Check Health Endpoints **From your local machine:** ```bash # Basic health check curl https://remote-agent.yourdomain.com/health # Expected: {"status":"ok"} # Database connectivity curl https://remote-agent.yourdomain.com/health/db # Expected: {"status":"ok","database":"connected"} # Concurrency status curl https://remote-agent.yourdomain.com/health/concurrency # Expected: {"status":"ok","active":0,"queued":0,"maxConcurrent":10} ``` ### Check SSL Certificate Visit `https://remote-agent.yourdomain.com/health` in your browser: - Should show green padlock - Certificate issued by "Let's Encrypt" - Auto-redirect from HTTP to HTTPS ### Check Telegram (if configured) Message your bot on Telegram: ``` /help ``` Should receive bot response with available commands. --- ## 9. Configure GitHub Webhooks Now that your app has a public URL, configure GitHub webhooks. ### Generate Webhook Secret (if not done earlier) ```bash # On server openssl rand -hex 32 # Copy output to .env as WEBHOOK_SECRET if not already set ``` ### Add Webhook to Repository 1. Go to: `https://github.com/owner/repo/settings/hooks` 2. Click "Add webhook" **Webhook Configuration:** | Field | Value | | -------------------- | ---------------------------------------------------------------------------- | | **Payload URL** | `https://remote-agent.yourdomain.com/webhooks/github` | | **Content type** | `application/json` | | **Secret** | Your `WEBHOOK_SECRET` from `.env` | | **SSL verification** | Enable SSL verification | | **Events** | Select individual events:
✓ Issues
✓ Issue comments
✓ Pull requests | 3. Click "Add webhook" 4. Check "Recent Deliveries" tab for successful delivery (green checkmark) **Test webhook:** Comment on an issue: ``` @your-bot-name can you analyze this issue? ``` Bot should respond with analysis. **For detailed webhook configuration, see [Platform Setup](../README.md#3-platform-adapter-setup-choose-at-least-one#github-webhooks).** --- ## 10. Maintenance & Operations ### View Logs ```bash # All services docker compose -f docker-compose.yml -f docker-compose.cloud.yml logs -f # Specific service docker compose -f docker-compose.yml -f docker-compose.cloud.yml logs -f app docker compose -f docker-compose.yml -f docker-compose.cloud.yml logs -f caddy # Last 100 lines docker compose -f docker-compose.yml -f docker-compose.cloud.yml logs --tail=100 app ``` ### Update Application ```bash # Pull latest changes cd /remote-coding-agent git pull # Rebuild and restart docker compose -f docker-compose.yml -f docker-compose.cloud.yml up -d --build # Check logs docker compose -f docker-compose.yml -f docker-compose.cloud.yml logs -f app ``` ### Restart Services ```bash # Restart all services docker compose -f docker-compose.yml -f docker-compose.cloud.yml restart # Restart specific service docker compose -f docker-compose.yml -f docker-compose.cloud.yml restart app docker compose -f docker-compose.yml -f docker-compose.cloud.yml restart caddy ``` ### Stop Services ```bash # Stop all services docker compose -f docker-compose.yml -f docker-compose.cloud.yml down # Stop and remove volumes (caution: deletes data) docker compose -f docker-compose.yml -f docker-compose.cloud.yml down -v ``` --- ## Troubleshooting ### Caddy Not Getting SSL Certificate **Check DNS:** ```bash dig remote-agent.yourdomain.com # Should return your server IP ``` **Check firewall:** ```bash sudo ufw status # Should allow ports 80 and 443 ``` **Check Caddy logs:** ```bash docker compose -f docker-compose.yml -f docker-compose.cloud.yml logs caddy # Look for certificate issuance attempts ``` **Common issues:** - DNS not propagated yet (wait 5-60 minutes) - Firewall blocking ports 80/443 - Domain typo in Caddyfile - A record not pointing to correct IP ### App Not Responding **Check if running:** ```bash docker compose -f docker-compose.yml -f docker-compose.cloud.yml ps # Should show 'app' and 'caddy' with state 'Up' ``` **Check health endpoint:** ```bash curl http://localhost:3090/health # Tests app directly (bypasses Caddy) ``` **Check logs:** ```bash docker compose -f docker-compose.yml -f docker-compose.cloud.yml logs -f app ``` ### Database Connection Errors **For remote database:** ```bash # Test connection from server psql $DATABASE_URL -c "SELECT 1" ``` **Check environment variable:** ```bash # View .env (don't share output publicly) cat .env | grep DATABASE_URL ``` **Run migrations if tables missing:** ```bash psql $DATABASE_URL < migrations/001_initial_schema.sql ``` ### GitHub Webhook Not Working **Check webhook deliveries:** 1. Go to webhook settings in GitHub 2. Click "Recent Deliveries" 3. Look for error messages **Verify webhook secret:** ```bash cat .env | grep WEBHOOK_SECRET # Must match GitHub webhook configuration ``` **Test webhook endpoint:** ```bash curl https://remote-agent.yourdomain.com/webhooks/github # Should return 400 (missing signature) - means endpoint is reachable ``` ### Out of Disk Space **Check disk usage:** ```bash df -h docker system df ``` **Clean up Docker:** ```bash # Remove unused images and containers docker system prune -a # Remove unused volumes (caution) docker volume prune ```