diff --git a/openhands/usage/agent-canvas/backend-setup/docker.mdx b/openhands/usage/agent-canvas/backend-setup/docker.mdx index 7e72170d..99454964 100644 --- a/openhands/usage/agent-canvas/backend-setup/docker.mdx +++ b/openhands/usage/agent-canvas/backend-setup/docker.mdx @@ -80,5 +80,4 @@ Then add the Docker backend: - [Connect and Manage Backends](/openhands/usage/agent-canvas/backends) - [Local Backend](/openhands/usage/agent-canvas/backend-setup/local) -- [VM Backend](/openhands/usage/agent-canvas/backend-setup/vm) -- [VM / Self-Hosted Backend](/openhands/usage/agent-canvas/backend-setup/vm) +- [VM / Self-Hosted Installation](/openhands/usage/agent-canvas/backend-setup/vm) diff --git a/openhands/usage/agent-canvas/backend-setup/local.mdx b/openhands/usage/agent-canvas/backend-setup/local.mdx index 4d18882c..a6bf67a4 100644 --- a/openhands/usage/agent-canvas/backend-setup/local.mdx +++ b/openhands/usage/agent-canvas/backend-setup/local.mdx @@ -48,6 +48,5 @@ Switch between them from the backend selector depending on what you're working o ## Related Guides - [Connect and Manage Backends](/openhands/usage/agent-canvas/backends) -- [VM Backend](/openhands/usage/agent-canvas/backend-setup/vm) — headless backend on a remote machine -- [VM / Self-Hosted Backend](/openhands/usage/agent-canvas/backend-setup/vm) — backend on a remote machine +- [VM / Self-Hosted Installation](/openhands/usage/agent-canvas/backend-setup/vm) — backend-only or full Canvas on a remote machine - [Docker Backend](/openhands/usage/agent-canvas/backend-setup/docker) — run in a container diff --git a/openhands/usage/agent-canvas/backend-setup/vm.mdx b/openhands/usage/agent-canvas/backend-setup/vm.mdx index 79ab742a..b71781f0 100644 --- a/openhands/usage/agent-canvas/backend-setup/vm.mdx +++ b/openhands/usage/agent-canvas/backend-setup/vm.mdx @@ -1,108 +1,261 @@ --- -title: VM / Self-Hosted Backend -description: Run Agent Canvas on a VM or dedicated machine and connect to it remotely. +title: VM / Self-Hosted Installation +description: Install Agent Canvas on a VM as a backend-only service or full self-hosted Canvas. --- -Use `--backend-only` to run the backend on a remote machine, then connect from your local frontend with `--frontend-only`. +Run Agent Canvas on a VM or dedicated machine when you want an always-on backend, more compute, or a self-hosted Canvas that you can reach from other devices. - The agent server can read and write the host filesystem, execute shell commands, and access the network. Lock down the machine before starting. + The agent server can read and write the host filesystem, execute shell commands, access the network, and store secrets. Treat the VM as trusted infrastructure. Use `--public`, a strong `LOCAL_BACKEND_API_KEY`, and a network access control layer before exposing it to the internet. -## 1. Provision and Secure the Machine +## Choose a Deployment Shape -Any always-on Linux or macOS host: +Agent Canvas supports two VM runtime modes and several ways to reach them: -- **Cloud VM** — Ubuntu 24.04 LTS, 2 vCPU / 4 GB RAM is enough for a single user. -- **Dedicated hardware** — Mac Mini, Intel NUC, spare laptop. +| Setup | Start Command | How You Use It | +|-------|---------------|----------------| +| **Backend only** | `agent-canvas --backend-only --public` | Run only the agent server on the VM. Start `agent-canvas --frontend-only` on your laptop and add the VM URL in **Manage Backends**. | +| **Backend only + ngrok** | `agent-canvas --backend-only --public` and `ngrok http 8000` | Use an ngrok URL as the backend URL. Do not add ngrok OAuth for this mode; rely on `LOCAL_BACKEND_API_KEY` plus a private or temporary URL. | +| **Full Canvas** | `agent-canvas --public` | Serve both the Agent Canvas UI and the backend from the VM. Open the VM, reverse proxy, or ngrok URL in a browser. | +| **Full Canvas + ngrok OAuth** | `agent-canvas --public` and `ngrok http 8000 --traffic-policy-file ~/policy.yml` | Protect the full Canvas URL with an ngrok login policy before users reach Agent Canvas. | -Lock down inbound traffic **before** starting the backend: + + Use **backend only** when you want to keep the UI on your laptop and switch between backends. Use **full Canvas** when the VM should serve the browser UI too. + + +## 1. Provision and Secure the VM + +Use any always-on Linux or macOS host. Ubuntu 24.04 LTS with 2 vCPU and 4 GB RAM is enough for a single user. -- **Port 22 (SSH)** — your IP or VPN CIDR only. -- **Everything else** — drop. +Before starting Agent Canvas, restrict inbound traffic: + +- **SSH (`22`)** — allow only your IP address or VPN CIDR. +- **Agent Canvas (`8000`)** — keep closed unless you are using an SSH tunnel. If you expose it through ngrok, nginx, or another proxy, expose only that proxy. +- **HTTP/HTTPS (`80`, `443`)** — open only if you configure a reverse proxy and TLS. ## 2. Install Prerequisites -On Ubuntu: +Agent Canvas requires: + +- [Node.js](https://nodejs.org/en/download) 22.12 or later, including `npm`. +- [`uv`](https://docs.astral.sh/uv/getting-started/installation/) for the agent server runtime. +- `git` and `curl`. +- Optional: [`ngrok`](https://ngrok.com/download) for a temporary public URL. +- Optional: `tmux` to keep Agent Canvas and ngrok running after disconnecting from SSH. + +### Ubuntu 22.04 / 24.04 + +Install Node.js 22.x, `uv`, and Agent Canvas: ```bash -apt-get update && apt-get install -y curl git +sudo apt-get update +sudo apt-get install -y ca-certificates curl gnupg git + +# Node.js 22.x from NodeSource. +curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - +sudo apt-get install -y nodejs -# Node.js 22.x (via nvm, asdf, or NodeSource) -# uv (for the agent server runtime): +# uv for the agent server runtime. curl -LsSf https://astral.sh/uv/install.sh | sh +source "$HOME/.local/bin/env" + +# Agent Canvas CLI. +sudo npm install -g @openhands/agent-canvas + +node --version +uv --version +agent-canvas --version ``` -On macOS, install Node and `uv` via Homebrew instead. + + If your `npm` global prefix is user-writable, omit `sudo` from `npm install -g`. For macOS or other Linux distributions, use the official Node.js, `uv`, and ngrok installation links above instead of the Ubuntu-specific commands. + -## 3. Start the Backend +Install optional runtime helpers if needed: ```bash -LOCAL_BACKEND_API_KEY= npx @openhands/agent-canvas --backend-only --public +sudo apt-get install -y tmux ``` -- `--backend-only` starts only the backend (no frontend). -- `--public` requires `LOCAL_BACKEND_API_KEY` — every API request must carry a matching `X-Session-API-Key` header. +Install ngrok only if you plan to expose the VM through ngrok: - - To also serve the UI from the VM (e.g. to access it from a phone), drop `--backend-only`. With the full stack, `--public` requires users to enter the API key in the UI before interacting with the agent. - +```bash +curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \ + | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null -## 4. Connect from Your Local Machine +echo "deb https://ngrok-agent.s3.amazonaws.com buster main" \ + | sudo tee /etc/apt/sources.list.d/ngrok.list -On your laptop, start the frontend: +sudo apt-get update +sudo apt-get install -y ngrok + +ngrok config add-authtoken +``` + +Get the authtoken from the [ngrok dashboard](https://dashboard.ngrok.com/get-started/your-authtoken). + +## 3. Set the Backend API Key + +Remote and shared deployments should always run in public mode. Public mode requires `LOCAL_BACKEND_API_KEY`. + +Create a local environment file on the VM: ```bash -agent-canvas --frontend-only +cat > ~/.agent-canvas.env <<'EOF_ENV' +export LOCAL_BACKEND_API_KEY="" +EOF_ENV +chmod 600 ~/.agent-canvas.env +source ~/.agent-canvas.env ``` -Then add the VM as a backend: +Use a high-entropy secret. You will enter this key in Agent Canvas when connecting to the VM backend or opening the full Canvas UI. + +## 4. Start Agent Canvas + + + + Start only the backend on the VM: + + ```bash + source ~/.agent-canvas.env + agent-canvas --backend-only --public + ``` + + Then start the frontend on your laptop: + + ```bash + agent-canvas --frontend-only + ``` + + Add the VM backend in Agent Canvas: + + 1. Click the backend switcher, then select `Manage Backends`. + 2. Click `Add Backend`. + 3. Enter a name, such as `my-vm`. + 4. Enter the **Host / Base URL**: + - `http://localhost:8000` if you use an SSH tunnel. + - The `https://...ngrok-free.app` URL if you use ngrok. + - Your reverse proxy URL if you use nginx or another proxy. + 5. Enter the `LOCAL_BACKEND_API_KEY` from the VM. + 6. Save and select the backend. + + + Start the full UI and backend on the VM: -1. Click the backend switcher → **Manage Backends** → **Add Backend**. -2. Fill in: - - **Name** — e.g. `my-vm` - - **Host / Base URL** — `http://localhost:8000` (if using an SSH tunnel) or the VM's URL if you've set up a reverse proxy - - **API Key** — the `LOCAL_BACKEND_API_KEY` from step 3 -3. Save and select it as the active backend. + ```bash + source ~/.agent-canvas.env + agent-canvas --public + ``` -### Using an SSH Tunnel + Open the VM, reverse proxy, or ngrok URL in a browser. Agent Canvas prompts for the `LOCAL_BACKEND_API_KEY` before allowing backend access. + + -The simplest way to reach the backend without exposing ports: +### Keep It Running with tmux + +Use `tmux` when you want Agent Canvas to keep running after your SSH session disconnects. + + + + ```bash + tmux new-session -d -s canvas + tmux send-keys -t canvas 'source ~/.agent-canvas.env && agent-canvas --backend-only --public' Enter + tmux attach-session -t canvas + ``` + + + ```bash + tmux new-session -d -s canvas + tmux send-keys -t canvas 'source ~/.agent-canvas.env && agent-canvas --public' Enter + tmux attach-session -t canvas + ``` + + + +Detach from tmux with `Ctrl-b`, then `d`. Reattach later with `tmux attach-session -t canvas`. + +## 5. Choose an Access Method + +### Option A: SSH Tunnel + +Use an SSH tunnel when you only need personal access and do not want to expose a public URL. + +On your laptop: ```bash ssh -L 8000:127.0.0.1:8000 user@your-vm ``` -Then use `http://localhost:8000` as the backend URL. +Then use `http://localhost:8000` as the backend URL in **Manage Backends**. -## 5. (Optional) Add a Domain with nginx + TLS +### Option B: ngrok Without OAuth -If you want direct HTTPS access without an SSH tunnel, point a domain at the machine and front it with nginx + Let's Encrypt. +Use ngrok without OAuth only for temporary testing or personal access. Keep `--public` enabled and use a strong `LOCAL_BACKEND_API_KEY`. -### Point a Domain at the Machine - -Create an `A` record pointing to the machine's public IP (e.g. `canvas.example.com`): +On the VM, in a second terminal or tmux pane: ```bash -dig +short canvas.example.com +ngrok http 8000 ``` -### Open Ports 80 and 443 +Use the `https://...ngrok-free.app` forwarding URL: + +- Backend-only mode: enter it as the **Host / Base URL** in **Manage Backends**. +- Full Canvas mode: open it directly in your browser. + +### Option C: ngrok With Google OAuth + +Use ngrok OAuth with **full Canvas** deployments when the ngrok URL may be reachable by a team or a broader audience. OAuth is an additional gate in front of Agent Canvas; it does not replace `LOCAL_BACKEND_API_KEY`. -Update your network firewall to additionally allow: +For backend-only deployments, use ngrok without OAuth and keep `--public` enabled. OAuth is best suited to the full Canvas URL where the UI and backend share the same origin. -- **Port 80 (HTTP)** — open to `0.0.0.0/0` (required for Let's Encrypt HTTP-01 challenges). nginx redirects all HTTP to HTTPS. -- **Port 443 (HTTPS)** — restrict to your IP if possible. If you need it world-open, `LOCAL_BACKEND_API_KEY` is your primary defense. +Create `~/policy.yml`, replacing `openhands.dev` with your allowed Google Workspace domain: + +```yaml +on_http_request: + # Require Google OAuth login. + - actions: + - type: oauth + config: + provider: google + + # Deny anyone outside the allowed domain. + - expressions: + - "!actions.ngrok.oauth.identity.email.endsWith('@openhands.dev')" + actions: + - type: deny + config: + status_code: 403 +``` -### Install nginx and Certbot +Start ngrok with the traffic policy: ```bash -apt-get install -y nginx certbot python3-certbot-nginx +ngrok http 8000 --traffic-policy-file ~/policy.yml ``` -### Configure nginx +To run full Canvas and ngrok side by side in tmux: -Save this at `/etc/nginx/sites-available/canvas.example.com`, replacing the domain: +```bash +tmux new-session -d -s canvas +tmux send-keys -t canvas 'source ~/.agent-canvas.env && agent-canvas --public' Enter +tmux split-window -h -t canvas +tmux send-keys -t canvas 'ngrok http 8000 --traffic-policy-file ~/policy.yml' Enter +tmux attach-session -t canvas +``` + +### Option D: Reverse Proxy With TLS + +Use a reverse proxy when you need a stable domain instead of an ngrok URL. Point a domain at the VM, proxy it to `127.0.0.1:8000`, and terminate TLS at the proxy. + +On Ubuntu, install nginx and Certbot: + +```bash +sudo apt-get install -y nginx certbot python3-certbot-nginx +``` + +Create `/etc/nginx/sites-available/canvas.example.com`, replacing `canvas.example.com` with your domain: ```nginx server { @@ -122,7 +275,7 @@ server { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; - # WebSocket / SSE support — required for live agent events. + # WebSocket / SSE support for live agent events. proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; @@ -134,36 +287,33 @@ server { Enable the site and issue a certificate: ```bash -ln -sf /etc/nginx/sites-available/canvas.example.com \ - /etc/nginx/sites-enabled/canvas.example.com -nginx -t && systemctl reload nginx - -certbot --nginx -d canvas.example.com \ - --non-interactive --agree-tos \ - --email you@example.com \ - --redirect -``` - -### Verify - -```bash -curl -I https://canvas.example.com/ # → 200 -curl -I http://canvas.example.com/ # → 301 redirect to HTTPS +sudo ln -sf /etc/nginx/sites-available/canvas.example.com \ + /etc/nginx/sites-enabled/canvas.example.com +sudo nginx -t +sudo systemctl reload nginx + +sudo certbot --nginx -d canvas.example.com \ + --non-interactive --agree-tos \ + --email you@example.com \ + --redirect ``` -Use `https://canvas.example.com` as the **Host / Base URL** when adding the backend in Manage Backends. +Use `https://canvas.example.com` as the URL for either the remote backend entry or the full Canvas UI. ## Security Checklist -Before exposing the backend to a broader network: +Before exposing Agent Canvas beyond an SSH tunnel: -1. **Restrict inbound network access** — only open ports you need (SSH, 80/443 for the reverse proxy). -2. **Use `--public` mode** with a strong `LOCAL_BACKEND_API_KEY`. -3. **Use TLS** — put a reverse proxy in front with Let's Encrypt if the backend is internet-reachable. -4. **Treat the host as sensitive infrastructure** — it stores secrets, conversations, and working copies. +1. **Run with `--public`** and set a strong `LOCAL_BACKEND_API_KEY`. +2. **Restrict network access** with a firewall, VPN, ngrok OAuth, or an identity-aware proxy. +3. **Use HTTPS** for any internet-reachable URL. +4. **Limit who can SSH to the VM** and keep the OS patched. +5. **Protect the VM filesystem** because it stores settings, secrets, conversations, and working copies. +6. **Rotate keys** if an ngrok URL, API key, or VM login is shared too broadly. ## Related Guides +- [Install](/openhands/usage/agent-canvas/setup) - [Connect and Manage Backends](/openhands/usage/agent-canvas/backends) - [Local Backend](/openhands/usage/agent-canvas/backend-setup/local) - [Docker Backend](/openhands/usage/agent-canvas/backend-setup/docker) diff --git a/openhands/usage/agent-canvas/backends.mdx b/openhands/usage/agent-canvas/backends.mdx index b2741b43..a3693eee 100644 --- a/openhands/usage/agent-canvas/backends.mdx +++ b/openhands/usage/agent-canvas/backends.mdx @@ -17,5 +17,5 @@ Settings, LLM configuration, MCP servers, and automations are all scoped to the |-------|-------------|-----| | **Default local** | Quick local work on your machine | Run `agent-canvas` — a local backend is created automatically | | **Backend-only (local)** | Multiple projects, or separate frontend and backend processes | Run `agent-canvas --backend-only` (optionally on different ports), connect with `--frontend-only`. See [Local Backend](/openhands/usage/agent-canvas/backend-setup/local). | -| **Backend-only (remote)** | Always-on server, more powerful hardware, or team-shared access | Run `agent-canvas --backend-only --public` on a VM with a `LOCAL_BACKEND_API_KEY`, connect via SSH tunnel or reverse proxy. See [VM / Self-Hosted Backend](/openhands/usage/agent-canvas/backend-setup/vm). | +| **Self-hosted VM** | Always-on server, more powerful hardware, team-shared access, or a full self-hosted Canvas | Run `agent-canvas --backend-only --public` for backend-only mode, or `agent-canvas --public` for the full UI and backend. Expose it with SSH, ngrok, or a reverse proxy. See [VM / Self-Hosted Installation](/openhands/usage/agent-canvas/backend-setup/vm). | | **Cloud** | Managed sandboxes without local resources | Connect to [OpenHands Cloud](/openhands/usage/cloud/openhands-cloud) from **Manage Backends**. See [Cloud Backend](/openhands/usage/agent-canvas/backend-setup/cloud). | diff --git a/openhands/usage/agent-canvas/overview.mdx b/openhands/usage/agent-canvas/overview.mdx index 65a62795..92a8eb91 100644 --- a/openhands/usage/agent-canvas/overview.mdx +++ b/openhands/usage/agent-canvas/overview.mdx @@ -36,4 +36,4 @@ description: A lightweight platform to run agents and automations — locally or - [Connect and Manage Backends](/openhands/usage/agent-canvas/backends) — Switch between local and remote backends. - [Customize and Settings](/openhands/usage/agent-canvas/customize-and-settings) — Configure skills, MCP servers, and backend-synced settings. - [Setup a Pre-built Automation](/openhands/usage/agent-canvas/prebuilt-automations) — Get started with a ready-made automation workflow. -- [VM / Self-Hosted Backend](/openhands/usage/agent-canvas/backend-setup/vm) — Run a backend on a VM and connect remotely. +- [VM / Self-Hosted Installation](/openhands/usage/agent-canvas/backend-setup/vm) — Run backend-only or full Canvas on a VM and connect remotely. diff --git a/openhands/usage/agent-canvas/setup.mdx b/openhands/usage/agent-canvas/setup.mdx index f86ecfdc..f05cd008 100644 --- a/openhands/usage/agent-canvas/setup.mdx +++ b/openhands/usage/agent-canvas/setup.mdx @@ -4,7 +4,7 @@ description: Install and run Agent Canvas via npm or Docker. --- - Agent Canvas starts an agent server on the machine where you run it. Treat that machine as trusted infrastructure and review the guidance in [VM / Self-Hosted Backend](/openhands/usage/agent-canvas/backend-setup/vm) before exposing it to a network you do not control. + Agent Canvas starts an agent server on the machine where you run it. Treat that machine as trusted infrastructure and review the guidance in [VM / Self-Hosted Installation](/openhands/usage/agent-canvas/backend-setup/vm) before exposing it to a network you do not control. @@ -28,7 +28,7 @@ description: Install and run Agent Canvas via npm or Docker. | Flag | Description | |------|-------------| | `-p`, `--port ` | Set the ingress port (default `8000`) | - | `--public` | Enable public mode — requires `LOCAL_BACKEND_API_KEY`. The key is **not** injected into the frontend; users must enter it when the UI loads. Use this for any deployment reachable by others. See [VM / Self-Hosted Backend](/openhands/usage/agent-canvas/backend-setup/vm). | + | `--public` | Enable public mode — requires `LOCAL_BACKEND_API_KEY`. The key is **not** injected into the frontend; users must enter it when the UI loads. Use this for any deployment reachable by others. See [VM / Self-Hosted Installation](/openhands/usage/agent-canvas/backend-setup/vm). | | `--backend-only` | Start only the backend behind ingress (no frontend). Use this to run a headless backend on a VM or server. | | `--frontend-only` | Start only the static frontend behind ingress (no agent server or automation). Use this to point a local UI at a remote backend. | | `-v`, `--version` | Show the version number |