> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yourhq.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Gateways

> Docker hosts that run your agents, browsers, and daemons.

A gateway is a Docker host that runs agents on infrastructure you control. Each gateway is a self-contained runtime environment — agents, browsers, files, and daemons all live inside it. The gateway runs OpenClaw v2026.6.6 as its agent runtime. The gateway has no direct network link to the UI; all coordination happens through Supabase.

## What's inside a gateway

A gateway deployment is a set of Docker containers that work together:

<CardGroup cols={2}>
  <Card title="Gateway container" icon="server">
    Runs OpenClaw (agent runtime), Chrome/Chromium, XFCE desktop, noVNC (remote desktop), and the files API. This is where agents actually execute.
  </Card>

  <Card title="Dispatcher daemon" icon="inbox">
    Subscribes to `agent_inbox_items` via Supabase Realtime. When new work arrives (task assignments, comment mentions, routines), it wakes the right agent on this gateway. Includes burst-aware batch sizing, inbox deduplication, and backoff for unprovisioned agents to prevent resource exhaustion.
  </Card>

  <Card title="Runner daemon" icon="terminal">
    Subscribes to `agent_commands` via Supabase Realtime. Leases and executes lifecycle commands: provision, update, remove, provider auth, shell commands, gateway operations. Also runs heartbeat (every 30s) and secrets sync.
  </Card>

  <Card title="Embedder" icon="microchip">
    Runs a local embedding model (default: `BAAI/bge-small-en-v1.5`). Leases knowledge items pending indexing, generates vector embeddings, and creates chunks. HTTP server at `:9100`.
  </Card>

  <Card title="File processor" icon="file">
    Leases knowledge items with `kind='file'` and `processing_status='ready'`, downloads from Supabase Storage, extracts text (PDF, DOCX, XLSX, CSV, PPTX, TXT), and triggers embedding.
  </Card>

  <Card title="Shared state volume" icon="hard-drive">
    Holds OpenClaw config, the local bare git repo with per-agent branches, browser profiles, desktop files, auth tokens, and secrets.
  </Card>
</CardGroup>

## How gateways communicate

Gateways are **pull-based** — they don't receive inbound connections from the UI. All coordination flows through Supabase:

```
UI → writes to Supabase tables (agent_commands, agent_inbox_items, etc.)
         ↓ Supabase Realtime
Gateway daemons ← subscribe and process
         ↓
Gateway daemons → write results back to Supabase
         ↓
UI ← reads updated state
```

This means a gateway can run behind NAT, a firewall, or a VPN with no inbound ports open. The only requirement is outbound HTTPS to your Supabase project.

The one exception is **noVNC**: when you open an agent's remote desktop, the UI proxies WebSocket traffic to the gateway container over Docker's internal network (or Tailscale, if configured). This is the only direct connection between the UI and the gateway.

## Gateway lifecycle

### Boot sequence

When a gateway container starts, `entrypoint.sh` runs a multi-step boot sequence:

0. Resolve Supabase credentials (env, token exchange, or workspace registry)
   0b. **Restore from backup** — if no local agent state exists, check Supabase Storage for a previous backup and extract it (restores auth tokens, configs, secrets, Telegram pairing)
1. Seed the local bare git repo from `/opt/templates/` (or `$TEMPLATES_SOURCE`)
2. Optionally attach to `$GIT_REMOTE_URL` for branch backup
3. Optionally bring up Tailscale (`$TAILSCALE_AUTH_KEY`)
4. Run `openclaw onboard` (first boot only)
5. Patch `openclaw.json` with browser, channel, and plugin paths
6. Install the hq-bootstrap plugin
7. Start Xtigervnc + XFCE desktop
8. Start websockify → noVNC
9. Upsert this gateway's row in the `gateways` table with reachable URLs
10. Exec `openclaw gateway start` as the main process

On **shutdown** (SIGTERM), the entrypoint automatically backs up gateway state to Supabase Storage before forwarding the signal to child processes.

See [Gateway boot](/self-host/gateway-boot) for the detailed walkthrough.

### Heartbeat

The runner daemon writes `last_heartbeat_at` to the `gateways` table every 30 seconds. The UI uses this to show gateway health:

* **Healthy** (green) — heartbeat within 90 seconds
* **Stale** (amber) — status is `ready` but heartbeat is old
* **No signal** — gateway has never reported

If a gateway goes stale, its agents can still have pending work queued — it will be processed when the gateway comes back online.

### Keepalive (hosted/E2B)

For gateways running in hosted mode (E2B sandboxes), a keepalive daemon maintains the sandbox lifecycle. It performs periodic health checks and renewal requests to prevent the sandbox from being reclaimed. The keepalive supports pause/resume functionality — when no agents are actively running, the keepalive can be paused to reduce overhead, and it automatically resumes when new work arrives.

### Registration

Gateways register with Supabase via a one-time token exchange. The UI generates a token (Settings → Gateways → Add Gateway), the gateway installer calls `consume_gateway_token()` to atomically convert the token into a `gateways` row, and the gateway stores its `GATEWAY_ID` in `.env` for all future operations.

## One workspace, many gateways

A single HQ workspace can have multiple gateways on different hosts — different machines, different data centers, different continents. Each gateway registers itself in the `gateways` table with its reachable URLs, so the UI knows how to reach each one.

Agents are bound to a specific gateway via `gateway_id`. The dispatcher and runner filter their Supabase subscriptions by `GATEWAY_ID` — no gateway ever picks up another gateway's work.

Common multi-gateway patterns:

| Pattern              | Example                                                               |
| -------------------- | --------------------------------------------------------------------- |
| **Geo-distributed**  | US gateway for US agents, EU gateway for EU agents                    |
| **Capability-split** | GPU gateway for heavy tasks, lightweight gateway for messaging agents |
| **Dev / prod**       | Staging gateway for testing, production gateway for live agents       |
| **Team isolation**   | Marketing team gateway, engineering team gateway                      |

<Tip>
  Start with one gateway. You can add more later from Settings → Gateways without reconfiguring anything.
</Tip>

## Gateway state and persistence

Each gateway owns a Docker volume (`gateway-state`) that holds:

* **Git repo** — a bare repo with one branch per agent. Agent files, skills, memory, and identity all live here.
* **Browser profiles** — Chrome profiles persist cookies, logins, and localStorage across agent sessions.
* **Auth tokens** — model provider credentials (OpenAI, Anthropic, etc.) stored by OpenClaw.
* **Secrets** — decrypted `.env` files written by the secrets sync daemon (plaintext on disk, `chmod 0600`).
* **Desktop state** — XFCE config, wallpapers, shortcuts.

### Automatic backup & restore

Since v0.2.1, gateway state is automatically backed up to Supabase Storage on every shutdown and restored on fresh boot. The backup includes auth tokens, agent configs, secrets, and Telegram pairing data. It excludes `sessions` and `codex-home` directories to keep backups small.

Retention policy: **3 backups per gateway, 7-day max age**, newest-first restore with fallback to older backups if the most recent is corrupted. You can also trigger manual backups and view backup status from **Settings → Backups** in the UI.

If you lose the `gateway-state` volume, the gateway will automatically restore from the most recent backup on next boot — no manual intervention needed. Agents can also be reprovisioned from the database if no backup is available. Use `GIT_REMOTE_URL` to continuously back up agent branches to GitHub/Gitea for an additional layer of protection. See [Operations → Backing up](/self-host/operations#backing-up).

## Adding a gateway

The recommended path is UI-driven:

1. Settings → Gateways → **Add Gateway**.
2. Copy the generated installer command.
3. Run it on the new host.

See [Add a gateway](/self-host/add-gateway) for the full walkthrough, or [Networking](/self-host/networking) for how gateways connect.
