Files
openagent/INSTALL.md
Thomas Marchand 6389dccfc3 Add persistent settings storage for library_remote
Replace env-var-only LIBRARY_REMOTE configuration with disk-persisted
settings. The setting can now be edited in the dashboard Settings page,
with LIBRARY_REMOTE env var serving as initial default when no settings
file exists.

Changes:
- Add src/settings.rs for settings storage with JSON persistence
- Add src/api/settings.rs for settings API endpoints
- Update dashboard Settings page with editable library remote field
- Update library-unavailable component to link to Settings page
- Update documentation to recommend Settings page method
2026-01-17 18:01:23 +00:00

24 KiB
Raw Blame History

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):
    ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
    
  2. Display the public key for them to copy:
    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@<server-ip>

Verify you have SSH access before proceeding: ssh root@<server-ip> "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:

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

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

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

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:

apt install -y systemd-container debootstrap

Desktop automation (Xvfb/i3/Chromium screenshots/OCR) — recommended for browser control:

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 Agents default Playwright MCP runner prefers bunx

Install Bun:

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:

curl -fsSL https://opencode.ai/install | bash -s -- --no-modify-path

Optional: pin a version (recommended for servers):

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:

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:

[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:

systemctl daemon-reload
systemctl enable --now opencode.service

Test:

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.

OpenCode discovers skills from global locations (e.g. ~/.opencode/skill, ~/.config/opencode/skill) and from the project/mission directory .opencode/skill. To guarantee perworkspace skill usage, run OpenCode with an isolated HOME and keep global skill dirs empty.

  1. Create an isolated OpenCode home:
mkdir -p /var/lib/opencode
  1. Update opencode.service to use the isolated home:
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
  1. Point Open Agent at the same OpenCode config dir (see section 6):
OPENCODE_CONFIG_DIR=/var/lib/opencode/.config/opencode
  1. Move any old global skills out of the way (optional but recommended):
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
  1. Reload services:
systemctl daemon-reload
systemctl restart opencode.service
systemctl restart open_agent.service

Validation (on the server, from the repo root):

scripts/validate_skill_isolation.sh

3.3 Install oh-my-opencode (agent pack)

Install the default agent pack as root:

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:

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):

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

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.

mkdir -p /opt/open_agent
cd /opt/open_agent
git clone <YOUR_OPEN_AGENT_REPO_URL> 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:

# Fast dev loop (to a separate path)
rsync -az --delete \
  --exclude target --exclude .git --exclude dashboard/node_modules \
  /path/to/local-dev/ \
  root@<server-ip>:/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

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:

One way to bootstrap:

# 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:<your-org>/<your-library-repo>.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:<your-org>/<your-library-repo>.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:

mkdir -p /etc/open_agent
chmod 700 /etc/open_agent

Example (fill in your real values):

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:<your-org>/<your-library-repo>.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 wont 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:

[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:

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:

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 wont reach the internet or Tailscale control plane.

Create an override for ve-* interfaces:

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 <ext_if> with your public interface, e.g. enp0s31f6):

sysctl -w net.ipv4.ip_forward=1

iptables -t nat -A POSTROUTING -s 10.88.0.0/24 -o <ext_if> -j MASQUERADE
iptables -A FORWARD -s 10.88.0.0/24 -o <ext_if> -j ACCEPT
iptables -A FORWARD -d 10.88.0.0/24 -m state --state ESTABLISHED,RELATED -i <ext_if> -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 arent enabled, Tailscale will fail or affect the host instead of the workspace.

Enable + start:

systemctl daemon-reload
systemctl enable --now open_agent.service

Test:

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:

cd /opt/open_agent/vaduz-v1
bash scripts/install_desktop.sh

Or follow docs/DESKTOP_SETUP.md.


9) Updating

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)

cd /opt/open_agent/vaduz-v1
git fetch --tags origin
git checkout <version-tag>  # 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:

cd /opt/open_agent/vaduz-v1
git pull origin master
# ... build and install as above

9.3 Update OpenCode (replace binary, restart service)

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

Caddy automatically obtains and renews Let's Encrypt certificates.

Install Caddy:

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:

systemctl enable --now caddy

Caddy will automatically obtain TLS certificates for your domain.

10.2 Nginx (manual certificate setup)

Install Nginx and Certbot:

apt install -y nginx certbot python3-certbot-nginx

Create /etc/nginx/sites-available/openagent:

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:

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:

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

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

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

  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:

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