> ## Documentation Index
> Fetch the complete documentation index at: https://allhandsai-alona-ohe-slack-install-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# VM / Self-Hosted Backend

> Run Agent Canvas on a VM or dedicated machine and connect to it remotely.

Use `--backend-only` to run the backend on a remote machine, then connect from your local frontend with `--frontend-only`.

<Warning>
  The agent server can read and write the host filesystem, execute shell commands, and access the network. Lock down the machine before starting.
</Warning>

## 1. Provision and Secure the Machine

Any always-on Linux or macOS host:

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

Lock down inbound traffic **before** starting the backend:

* **Port 22 (SSH)** — your IP or VPN CIDR only.
* **Everything else** — drop.

## 2. Install Prerequisites

On Ubuntu:

```bash theme={null}
apt-get update && apt-get install -y curl git

# Node.js 22.x (via nvm, asdf, or NodeSource)
# uv (for the agent server runtime):
curl -LsSf https://astral.sh/uv/install.sh | sh
```

On macOS, install Node and `uv` via Homebrew instead.

## 3. Start the Backend

```bash theme={null}
LOCAL_BACKEND_API_KEY=<choose-a-strong-secret> npx @openhands/agent-canvas --backend-only --public
```

* `--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.

<Tip>
  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.
</Tip>

## 4. Connect from Your Local Machine

On your laptop, start the frontend:

```bash theme={null}
agent-canvas --frontend-only
```

Then add the VM as a backend:

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.

### Using an SSH Tunnel

The simplest way to reach the backend without exposing ports:

```bash theme={null}
ssh -L 8000:127.0.0.1:8000 user@your-vm
```

Then use `http://localhost:8000` as the backend URL.

## 5. (Optional) Add a Domain with nginx + TLS

If you want direct HTTPS access without an SSH tunnel, point a domain at the machine and front it with nginx + Let's Encrypt.

### Point a Domain at the Machine

Create an `A` record pointing to the machine's public IP (e.g. `canvas.example.com`):

```bash theme={null}
dig +short canvas.example.com
```

### Open Ports 80 and 443

Update your network firewall to additionally allow:

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

### Install nginx and Certbot

```bash theme={null}
apt-get install -y nginx certbot python3-certbot-nginx
```

### Configure nginx

Save this at `/etc/nginx/sites-available/canvas.example.com`, replacing the domain:

```nginx theme={null}
server {
    listen 80;
    listen [::]:80;
    server_name canvas.example.com;

    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        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;

        # WebSocket / SSE support — required for live agent events.
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}
```

Enable the site and issue a certificate:

```bash theme={null}
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 theme={null}
curl -I https://canvas.example.com/      # → 200
curl -I http://canvas.example.com/       # → 301 redirect to HTTPS
```

Use `https://canvas.example.com` as the **Host / Base URL** when adding the backend in Manage Backends.

## Security Checklist

Before exposing the backend to a broader network:

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.

## Related Guides

* [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)
* [Cloud Backend](/openhands/usage/agent-canvas/backend-setup/cloud)
