# Installing Open Agent (Ubuntu 24.04, dedicated server) This is the installation approach currently used on a **dedicated Ubuntu 24.04 server** (OpenCode + Open Agent running on the same machine, managed by `systemd`). Open Agent is the orchestrator/UI backend. **It does not run model inference**; it delegates execution to an **OpenCode server** running locally (default `http://127.0.0.1:4096`). > **For AI Agents**: Before starting this installation, ask the user to provide: > 1. **Server IP address** (e.g., `95.216.112.253`) > 2. **Domain name** pointing to that IP (e.g., `agent.example.com`) > 3. **SSH access** credentials or key path for the server > 4. **Library git repo URL** (or confirm using the template) > 5. **Dashboard password** to set for authentication (or offer to generate one) > > **SSH Key Setup**: Most servers require SSH key authentication. If the user doesn't have one: > 1. Generate a key (without passphrase for easier automation): > ```bash > ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" > ``` > 2. Display the public key for them to copy: > ```bash > cat ~/.ssh/id_ed25519.pub > ``` > 3. They need to add this key to their server. Options: > - **Hosting provider dashboard**: Most providers (Hetzner, DigitalOcean, Vultr, etc.) have an "SSH Keys" section in their web console > - **Existing access**: If they can already log in: `ssh-copy-id root@` > > Verify you have SSH access before proceeding: `ssh root@ "hostname"` > > If connection fails, common causes: > - The SSH key wasn't added to the server (check hosting provider's dashboard) > - The key has a passphrase (agent tools may not handle passphrase prompts) > - Firewall blocking port 22 (check hosting provider's firewall settings) --- ## 0) Assumptions - Ubuntu 24.04 LTS, root SSH access - A dedicated server (not shared hosting) - You want: - OpenCode server bound to localhost: `127.0.0.1:4096` - Open Agent bound to: `0.0.0.0:3000` - You have a Git repo for your **Library** (skills/tools/agents/rules/MCP configs) > **Recommendation**: Unless you know exactly what you need, install **all components** in this guide: > - **Bun** (required for OpenCode plugins and Playwright MCP) > - **systemd-container + debootstrap** (for isolated container workspaces) > - **Desktop automation tools** (Xvfb, i3, Chromium, xdotool, etc.) > - **Reverse proxy with SSL** (Caddy or Nginx + Certbot) > > Skipping components may limit functionality. The full installation uses ~2-3 GB of disk space. --- ## 0.5) DNS & Domain Setup (before you begin) Before starting the installation, ensure your domain is configured: ### 0.5.1 Point your domain to the server Add an A record in your DNS provider: ``` agent.yourdomain.com → A → YOUR_SERVER_IP ``` Example with common providers: - **Cloudflare**: DNS → Add Record → Type: A, Name: `agent`, IPv4: `YOUR_SERVER_IP` - **Namecheap**: Advanced DNS → Add New Record → A Record - **Route53**: Create Record → Simple routing → A record ### 0.5.2 Verify DNS propagation Wait for DNS to propagate (usually 1-15 minutes), then verify: ```bash # From your local machine dig +short agent.yourdomain.com # Should return your server IP # Or use an online checker curl -s "https://dns.google/resolve?name=agent.yourdomain.com&type=A" | jq . ``` ### 0.5.3 SSH key for Library repo (if private) If your Library repo is private, set up an SSH deploy key on the server: ```bash # On the server ssh-keygen -t ed25519 -C "openagent-server" -f /root/.ssh/openagent -N "" cat /root/.ssh/openagent.pub # Copy this public key ``` Add the public key as a **deploy key** in your git provider: - **GitHub**: Repository → Settings → Deploy keys → Add deploy key - **GitLab**: Repository → Settings → Repository → Deploy keys Configure SSH to use the key: ```bash cat >> /root/.ssh/config <<'EOF' Host github.com IdentityFile /root/.ssh/openagent IdentitiesOnly yes EOF # Test the connection ssh -T git@github.com ``` --- ## 1) Install base OS dependencies ```bash apt update apt install -y \ ca-certificates curl git jq unzip tar \ build-essential pkg-config libssl-dev ``` **Container workspaces** (systemd-nspawn) — recommended for isolated environments: ```bash apt install -y systemd-container debootstrap ``` **Desktop automation** (Xvfb/i3/Chromium screenshots/OCR) — recommended for browser control: ```bash apt install -y xvfb i3 x11-utils xdotool scrot imagemagick chromium chromium-sandbox tesseract-ocr ``` See `docs/DESKTOP_SETUP.md` for i3 config and additional setup after installation. --- ## 2) Install Bun (for bunx + Playwright MCP) OpenCode is distributed as a binary, but: - OpenCode plugins are installed internally via Bun - Open Agent’s default Playwright MCP runner prefers `bunx` Install Bun: ```bash curl -fsSL https://bun.sh/install | bash # Make bun/bunx available to systemd services install -m 0755 /root/.bun/bin/bun /usr/local/bin/bun install -m 0755 /root/.bun/bin/bunx /usr/local/bin/bunx bun --version bunx --version ``` --- ## 3) Install OpenCode (server backend) ### 3.1 Install/Update the OpenCode binary This installs the latest release into `~/.opencode/bin/opencode`: ```bash curl -fsSL https://opencode.ai/install | bash -s -- --no-modify-path ``` Optional: pin a version (recommended for servers): ```bash curl -fsSL https://opencode.ai/install | bash -s -- --version 1.1.8 --no-modify-path ``` Copy the binary into a stable system location used by `systemd`: ```bash install -m 0755 /root/.opencode/bin/opencode /usr/local/bin/opencode opencode --version ``` ### 3.2 Create `systemd` unit for OpenCode Create `/etc/systemd/system/opencode.service`: ```ini [Unit] Description=OpenCode Server After=network.target [Service] Type=simple ExecStart=/usr/local/bin/opencode serve --port 4096 --hostname 127.0.0.1 WorkingDirectory=/root Restart=always RestartSec=10 Environment=HOME=/root [Install] WantedBy=multi-user.target ``` Enable + start: ```bash systemctl daemon-reload systemctl enable --now opencode.service ``` Test: ```bash curl -fsSL http://127.0.0.1:4096/global/health | jq . ``` Note: Open Agent will also keep OpenCode's global config updated (MCP + tool allowlist) in: `~/.config/opencode/opencode.json`. ### 3.2.1 Strong workspace skill isolation (recommended) OpenCode discovers skills from global locations (e.g. `~/.opencode/skill`, `~/.config/opencode/skill`) *and* from the project/mission directory `.opencode/skill`. To guarantee **per‑workspace** skill usage, run OpenCode with an isolated HOME and keep global skill dirs empty. 1) Create an isolated OpenCode home: ```bash mkdir -p /var/lib/opencode ``` 2) Update `opencode.service` to use the isolated home: ```ini Environment=HOME=/var/lib/opencode Environment=XDG_CONFIG_HOME=/var/lib/opencode/.config Environment=XDG_DATA_HOME=/var/lib/opencode/.local/share Environment=XDG_CACHE_HOME=/var/lib/opencode/.cache ``` 3) Point Open Agent at the same OpenCode config dir (see section 6): ``` OPENCODE_CONFIG_DIR=/var/lib/opencode/.config/opencode ``` 4) Move any old global skills out of the way (optional but recommended): ```bash mv /root/.opencode/skill /root/.opencode/skill.bak-$(date +%F) 2>/dev/null || true mv /root/.config/opencode/skill /root/.config/opencode/skill.bak-$(date +%F) 2>/dev/null || true ``` 5) Reload services: ```bash systemctl daemon-reload systemctl restart opencode.service systemctl restart open_agent.service ``` Validation (on the server, from the repo root): ```bash scripts/validate_skill_isolation.sh ``` ### 3.3 Install oh-my-opencode (agent pack) Install the default agent pack as root: ```bash bunx oh-my-opencode install --no-tui ``` This installs the **Sisyphus** default agent (plus other personalities). To preserve plugin defaults: Leave the Open Agent agent/model overrides unset to use the OpenCode / oh-my-opencode defaults. Update strategy: - Pin a version in your Library `plugins.json` (e.g., `oh-my-opencode@1.2.3`) to lock updates. - Otherwise, the plugin can auto-update via OpenCode's install hook and Open Agent sync. ### 3.4 Install opencode-gemini-auth (optional, for Google OAuth) If you want to authenticate with Google accounts (Gemini plans/quotas including free tier) via OAuth instead of API keys: ```bash bunx opencode-gemini-auth install ``` This enables OAuth-based Google authentication, allowing users to leverage their existing Gemini plan directly within OpenCode. Features include: - OAuth flow with Google accounts - Automatic Cloud project provisioning - Support for thinking capabilities (Gemini 2.5/3) To authenticate via CLI (useful for testing): ```bash opencode auth login # Select Google provider, then "OAuth with Google (Gemini CLI)" ``` For dashboard OAuth integration, see the Settings page which handles this flow via the API. --- ## 4) Install Open Agent (Rust backend) ### 4.1 Install Rust toolchain ```bash curl -fsSL https://sh.rustup.rs | sh -s -- -y source /root/.cargo/env rustc --version cargo --version ``` ### 4.2 Deploy the repository On the server we keep the repo under `/opt/open_agent/vaduz-v1`. **This must be a git clone** (not just copied files) for the dashboard's one-click update system to work. ```bash mkdir -p /opt/open_agent cd /opt/open_agent git clone vaduz-v1 ``` > **Important**: The update system in Settings relies on git tags to detect new releases. If you deploy via rsync without `.git`, the "Update Available" button won't work. Always use `git clone` for production deployments. For local development, you can rsync to a *different* path (e.g., `/root/open_agent`) for rapid iteration, but keep the git clone at `/opt/open_agent/vaduz-v1` for the update system: ```bash # Fast dev loop (to a separate path) rsync -az --delete \ --exclude target --exclude .git --exclude dashboard/node_modules \ /path/to/local-dev/ \ root@:/root/open_agent/ # The git clone at /opt/open_agent/vaduz-v1 is used by the update system ``` If you need to specify a custom SSH key, add `-e "ssh -i ~/.ssh/your_key"`. ### 4.3 Build and install binaries ```bash cd /opt/open_agent/vaduz-v1 source /root/.cargo/env # Debug build (fast) - recommended for rapid iteration cargo build --bin open_agent --bin workspace-mcp --bin desktop-mcp install -m 0755 target/debug/open_agent /usr/local/bin/open_agent install -m 0755 target/debug/workspace-mcp /usr/local/bin/workspace-mcp install -m 0755 target/debug/desktop-mcp /usr/local/bin/desktop-mcp # Or: Release build (slower compile, faster runtime) # cargo build --release --bin open_agent --bin workspace-mcp --bin desktop-mcp # install -m 0755 target/release/open_agent /usr/local/bin/open_agent # install -m 0755 target/release/workspace-mcp /usr/local/bin/workspace-mcp # install -m 0755 target/release/desktop-mcp /usr/local/bin/desktop-mcp ``` --- ## 5) Bootstrap the Library (config repo) Open Agent expects a git-backed **Library** repo. At runtime it will: - clone it into `LIBRARY_PATH` (default: `{WORKING_DIR}/.openagent/library`) - ensure the `origin` remote matches `LIBRARY_REMOTE` - pull/sync as needed ### 5.1 Create your own library repo from the template Template: - https://github.com/Th0rgal/openagent-library-template One way to bootstrap: ```bash # On your machine git clone git@github.com:Th0rgal/openagent-library-template.git openagent-library cd openagent-library # Point it at your own repo git remote set-url origin git@github.com:/.git # Push to your remote (choose main/master as you prefer) git push -u origin HEAD:main ``` ### 5.2 Configure Open Agent to use it **Option A: Via Dashboard Settings (recommended)** After starting Open Agent, go to **Settings** in the dashboard and set the Library Remote URL. This is the preferred method as it persists the setting to disk and allows runtime updates without restart. **Option B: Via environment variable (initial default)** Set in `/etc/open_agent/open_agent.env`: - `LIBRARY_REMOTE=git@github.com:/.git` (used as initial default if not configured in Settings) - optional: `LIBRARY_PATH=/root/.openagent/library` --- ## 6) Configure Open Agent (env file) Create `/etc/open_agent/open_agent.env`: ```bash mkdir -p /etc/open_agent chmod 700 /etc/open_agent ``` Example (fill in your real values): ```bash cat > /etc/open_agent/open_agent.env <<'EOF' # OpenCode backend (must match opencode.service) OPENCODE_BASE_URL=http://127.0.0.1:4096 OPENCODE_PERMISSIVE=true # Optional: keep Open Agent writing OpenCode global config into the isolated home # (recommended if you enabled strong workspace skill isolation in section 3.2.1). # OPENCODE_CONFIG_DIR=/var/lib/opencode/.config/opencode # Server bind HOST=0.0.0.0 PORT=3000 # Default filesystem root for Open Agent (agent still has full system access) WORKING_DIR=/root LIBRARY_PATH=/root/.openagent/library # Library remote (optional, can also be set via dashboard Settings page) LIBRARY_REMOTE=git@github.com:/.git # Auth (set DEV_MODE=false on real deployments) DEV_MODE=false DASHBOARD_PASSWORD=change-me JWT_SECRET=change-me-to-a-long-random-string JWT_TTL_DAYS=30 # Dashboard Console (local shell) # No SSH configuration required. # Default model (provider/model). If omitted or not in provider/model format, # Open Agent won’t force a model and OpenCode will use its own defaults. # Desktop tools (optional) DESKTOP_ENABLED=true DESKTOP_RESOLUTION=1920x1080 EOF ``` --- ## 7) Create `systemd` unit for Open Agent Create `/etc/systemd/system/open_agent.service`: ```ini [Unit] Description=OpenAgent (managed control plane) After=network-online.target Wants=network-online.target [Service] Type=simple User=root Group=root EnvironmentFile=/etc/open_agent/open_agent.env WorkingDirectory=/root ExecStart=/usr/local/bin/open_agent Restart=on-failure RestartSec=2 # Agent needs full system access, minimal hardening NoNewPrivileges=false PrivateTmp=false ProtectHome=false [Install] WantedBy=multi-user.target ``` --- ## 8) Optional: Tailscale exit-node workspaces (residential IP) If you want a **workspace** to egress via a residential IP, the recommended pattern is: 1) Run a Tailscale **exit node** at home. 2) Use a workspace template that installs and starts Tailscale inside the container. ### 8.1 Enable the exit node at home On the home server: ```bash tailscale up --advertise-exit-node ``` Approve it in the Tailscale admin console (Machines → your node → “Approve exit node”). ### 8.2 Use the `residential` workspace template This repo ships a sample template at: ``` library-template/workspace-template/residential.json ``` It installs Tailscale and adds helper scripts: - `openagent-network-up` (brings up host0 veth + DHCP + DNS) - `openagent-tailscale-up` (starts tailscaled + sets exit node) - `openagent-tailscale-check` (prints Tailscale status + public IP) Set these **workspace env vars** (not global env): - `TS_AUTHKEY` (auth key for that workspace) - `TS_EXIT_NODE` (node name like `umbrel` or its 100.x IP) - Optional: `TS_ACCEPT_DNS=true|false`, `TS_EXIT_NODE_ALLOW_LAN=false`, `TS_STATE_DIR=/var/lib/tailscale` Then inside the workspace: ```bash openagent-tailscale-up openagent-tailscale-check ``` If the public IP matches your home ISP, the exit node is working. ### 8.3 Host NAT for veth networking (required) `systemd-nspawn --network-veth` needs DHCP + NAT on the host. Without this, containers won’t reach the internet or Tailscale control plane. Create an override for `ve-*` interfaces: ```bash cat >/etc/systemd/network/80-container-ve.network <<'EOF' [Match] Name=ve-* [Network] Address=10.88.0.1/24 DHCPServer=yes EOF systemctl restart systemd-networkd ``` Enable forwarding + NAT (replace `` with your public interface, e.g. `enp0s31f6`): ```bash sysctl -w net.ipv4.ip_forward=1 iptables -t nat -A POSTROUTING -s 10.88.0.0/24 -o -j MASQUERADE iptables -A FORWARD -s 10.88.0.0/24 -o -j ACCEPT iptables -A FORWARD -d 10.88.0.0/24 -m state --state ESTABLISHED,RELATED -i -j ACCEPT ``` Persist the iptables rules using `iptables-persistent` (or migrate to nftables). ### 8.4 Notes for container workspaces Tailscale inside a container requires: - `/dev/net/tun` bound into the container - `CAP_NET_ADMIN` - A private network namespace (not host network) If those aren’t enabled, Tailscale will fail or affect the host instead of the workspace. Enable + start: ```bash systemctl daemon-reload systemctl enable --now open_agent.service ``` Test: ```bash curl -fsSL http://127.0.0.1:3000/api/health | jq . ``` --- ## 8) Optional: Desktop automation dependencies If you want browser/desktop automation on Ubuntu, run: ```bash cd /opt/open_agent/vaduz-v1 bash scripts/install_desktop.sh ``` Or follow `docs/DESKTOP_SETUP.md`. --- ## 9) Updating ### 9.1 Update Open Agent via Dashboard (recommended) The Settings page shows available updates for Open Agent, OpenCode, and oh-my-opencode. When a new version is available: 1. Go to **Settings → System Components** 2. If "Update Available" appears, click the **Update** button 3. The update will: - Fetch the latest git tags from the repository - Checkout the newest release tag - Build the binaries (debug mode for faster compile) - Install and restart the service **Requirements for one-click updates:** - The repository at `/opt/open_agent/vaduz-v1` must be a git clone (not rsync'd files) - Create GitHub releases with version tags (e.g., `0.2.1` or `v0.2.1`) to trigger update detection - The server needs SSH access to pull from GitHub (deploy key configured in section 0.5.3) ### 9.2 Update Open Agent manually (CLI) ```bash cd /opt/open_agent/vaduz-v1 git fetch --tags origin git checkout # e.g., v0.2.1 source /root/.cargo/env cargo build --bin open_agent --bin workspace-mcp --bin desktop-mcp install -m 0755 target/debug/open_agent /usr/local/bin/open_agent install -m 0755 target/debug/workspace-mcp /usr/local/bin/workspace-mcp install -m 0755 target/debug/desktop-mcp /usr/local/bin/desktop-mcp systemctl restart open_agent.service ``` Or to follow the latest master branch: ```bash cd /opt/open_agent/vaduz-v1 git pull origin master # ... build and install as above ``` ### 9.3 Update OpenCode (replace binary, restart service) ```bash # Optionally pin a version curl -fsSL https://opencode.ai/install | bash -s -- --version 1.1.8 --no-modify-path install -m 0755 /root/.opencode/bin/opencode /usr/local/bin/opencode systemctl restart opencode.service curl -fsSL http://127.0.0.1:4096/global/health | jq . ``` ## 10) Production Security (TLS + Reverse Proxy) For production deployments, **always** put Open Agent behind a reverse proxy with TLS. The backend serves HTTP only and should never be exposed directly to the internet. ### 10.1 Caddy (recommended - automatic HTTPS) Caddy automatically obtains and renews Let's Encrypt certificates. Install Caddy: ```bash apt install -y debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list apt update && apt install caddy ``` Create `/etc/caddy/Caddyfile`: ``` agent.yourdomain.com { reverse_proxy localhost:3000 } ``` Enable and start: ```bash systemctl enable --now caddy ``` Caddy will automatically obtain TLS certificates for your domain. ### 10.2 Nginx (manual certificate setup) Install Nginx and Certbot: ```bash apt install -y nginx certbot python3-certbot-nginx ``` Create `/etc/nginx/sites-available/openagent`: ```nginx server { listen 80; server_name agent.yourdomain.com; location / { proxy_pass http://127.0.0.1:3000; 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; # SSE support (for mission streaming) proxy_buffering off; proxy_cache off; proxy_read_timeout 86400s; } } ``` Enable the site and obtain certificates: ```bash ln -s /etc/nginx/sites-available/openagent /etc/nginx/sites-enabled/ nginx -t && systemctl reload nginx certbot --nginx -d agent.yourdomain.com ``` ### 10.3 Firewall Block direct access to port 3000 from the internet: ```bash # Allow only localhost to reach Open Agent directly iptables -A INPUT -p tcp --dport 3000 -s 127.0.0.1 -j ACCEPT iptables -A INPUT -p tcp --dport 3000 -j DROP ``` --- ## 11) Authentication Modes Open Agent supports three authentication modes: | Mode | Environment Variables | Use Case | |------|----------------------|----------| | **Disabled** | `DEV_MODE=true` | Local development only | | **Single Tenant** | `DASHBOARD_PASSWORD`, `JWT_SECRET` | Personal server, one user | | **Multi-User** | `OPEN_AGENT_USERS`, `JWT_SECRET` | Shared server, multiple users | ### 11.1 Single Tenant (default for production) Set a strong password and JWT secret: ```bash # Generate a random JWT secret JWT_SECRET=$(openssl rand -base64 32) # In /etc/open_agent/open_agent.env: DEV_MODE=false DASHBOARD_PASSWORD=your-strong-password-here JWT_SECRET=$JWT_SECRET JWT_TTL_DAYS=30 ``` ### 11.2 Multi-User Mode For multiple users with separate credentials: ```bash # In /etc/open_agent/open_agent.env: DEV_MODE=false OPEN_AGENT_USERS='[ {"username": "alice", "password": "alice-strong-password"}, {"username": "bob", "password": "bob-strong-password"} ]' JWT_SECRET=$(openssl rand -base64 32) ``` Note: Multi-user mode provides separate login credentials but does **not** provide workspace or data isolation between users. All users see the same missions and workspaces. --- ## 12) Dashboard Configuration This guide installs the **backend** on your server. The dashboard (frontend) is separate and you have several options: | Option | Best For | Setup | |--------|----------|-------| | **Vercel** | Production, always accessible | Deploy `dashboard/` to Vercel | | **Local** | Development, quick testing | Run `bun dev` in dashboard folder | | **iOS App** | Mobile access | Enter backend URL in app | ### 12.1 Web Dashboard (Vercel) Deploy the `dashboard/` folder to [Vercel](https://vercel.com): 1. Connect your repo to Vercel 2. Set the root directory to `dashboard` 3. Add environment variable: `NEXT_PUBLIC_API_URL=https://agent.yourdomain.com` 4. Deploy The dashboard will connect to your backend server. ### 12.2 Web Dashboard (Local) Run the dashboard locally on your machine: ```bash cd dashboard bun install NEXT_PUBLIC_API_URL=https://agent.yourdomain.com bun dev ``` Then open `http://localhost:3000`. ### 12.3 iOS App On first launch, the iOS app prompts for the server URL. Enter your backend URL (e.g., `https://agent.yourdomain.com`). To change later: **Menu (⋮) → Settings** --- ## 13) OAuth Provider Setup Open Agent uses OAuth for AI provider authentication. The following providers are pre-configured: | Provider | OAuth Client | Setup Required | |----------|-------------|----------------| | **Anthropic** | OpenCode's client | None (works out of the box) | | **OpenAI** | Codex CLI client | None (works out of the box) | | **Google/Gemini** | Gemini CLI client | Install `opencode-gemini-auth` plugin | OAuth flows use copy-paste for the authorization code. The user: 1. Clicks "Authorize" in the dashboard 2. Completes OAuth in their browser 3. Copies the redirect URL back to the dashboard --- ## Checklist for Production Deployment - [ ] Set `DEV_MODE=false` - [ ] Set strong `DASHBOARD_PASSWORD` and `JWT_SECRET` - [ ] Configure reverse proxy (Caddy or Nginx) with TLS - [ ] Firewall port 3000 (only allow localhost) - [ ] Pin OpenCode version for stability - [ ] Set up your Library git repo - [ ] Test OAuth flows for AI providers