Skip to content
8 changes: 8 additions & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@
"docs/agents/amp",
"docs/agents/claude-code",
"docs/agents/codex",
{
"group": "OpenClaw",
"icon": "/images/icons/openclaw.svg",
"pages": [
"docs/agents/openclaw/openclaw-gateway",
"docs/agents/openclaw/openclaw-telegram"
]
},
"docs/agents/opencode"
]
},
Expand Down
277 changes: 277 additions & 0 deletions docs/agents/openclaw/openclaw-gateway.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
---
title: "Deploy OpenClaw"
description: "Start the OpenClaw gateway in an E2B sandbox and connect your browser."
icon: "globe"
---

## Quick start

This launches your OpenClaw [gateway](https://docs.openclaw.ai/gateway) site (web UI for chatting with agents).

<CodeGroup>
```typescript JavaScript & TypeScript
import { Sandbox } from 'e2b'

const TOKEN = process.env.OPENCLAW_APP_TOKEN || 'my-gateway-token'
const PORT = 18789

// 1. Create sandbox
const sandbox = await Sandbox.create('openclaw', {
envs: { OPENAI_API_KEY: process.env.OPENAI_API_KEY },
timeoutMs: 3600_000,
})

// 2. Set the default model
await sandbox.commands.run('openclaw config set agents.defaults.model.primary openai/gpt-5.2')

// 3. Set insecure control UI flags and start the gateway with token auth
await sandbox.commands.run(
`bash -lc 'openclaw config set gateway.controlUi.allowInsecureAuth true && ` +
`openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth true && ` +
`openclaw gateway --allow-unconfigured --bind lan --auth token --token ${TOKEN} --port ${PORT}'`,
{ background: true }
)

// 4. Wait for the gateway to start listening
for (let i = 0; i < 45; i++) {
const probe = await sandbox.commands.run(
`bash -lc 'ss -ltn | grep -q ":${PORT} " && echo ready || echo waiting'`
)
if (probe.stdout.trim() === 'ready') break
await new Promise((r) => setTimeout(r, 1000))
}

const url = `https://${sandbox.getHost(PORT)}/?token=${TOKEN}`
console.log(`Gateway: ${url}`)
```
```python Python
import os, time
from e2b import Sandbox

TOKEN = os.environ.get("OPENCLAW_APP_TOKEN", "my-gateway-token")
PORT = 18789

# 1. Create sandbox
sandbox = Sandbox.create("openclaw", envs={
"OPENAI_API_KEY": os.environ["OPENAI_API_KEY"],
}, timeout=3600)

# 2. Set the default model
sandbox.commands.run("openclaw config set agents.defaults.model.primary openai/gpt-5.2")

# 3. Set insecure control UI flags and start the gateway with token auth
sandbox.commands.run(
f"bash -lc 'openclaw config set gateway.controlUi.allowInsecureAuth true && "
f"openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth true && "
f"openclaw gateway --allow-unconfigured --bind lan --auth token --token {TOKEN} --port {PORT}'",
background=True,
)

# 4. Wait for the gateway to start listening
for _ in range(45):
probe = sandbox.commands.run(
f'bash -lc \'ss -ltn | grep -q ":{PORT} " && echo ready || echo waiting\''
)
if probe.stdout.strip() == "ready":
break
time.sleep(1)

url = f"https://{sandbox.get_host(PORT)}/?token={TOKEN}"
print(f"Gateway: {url}")
```
</CodeGroup>

Visit the printed `Gateway` URL in your browser.

If you run in secure mode (set `gateway.controlUi.dangerouslyDisableDeviceAuth false`), run this after opening the URL to poll pending pairing requests and approve the first one.

<CodeGroup>
```typescript JavaScript & TypeScript
// 5. Poll for the browser's pending device request and approve it
for (let i = 0; i < 30; i++) {
try {
const res = await sandbox.commands.run(
`openclaw devices list --json --url ws://127.0.0.1:${PORT} --token ${TOKEN}`
)
const data = JSON.parse(res.stdout)
if (data.pending?.length) {
const rid = data.pending[0].requestId
await sandbox.commands.run(
`openclaw devices approve ${rid} --token ${TOKEN} --url ws://127.0.0.1:${PORT}`
)
console.log(`Device approved: ${rid}`)
break
}
} catch {}
await new Promise((r) => setTimeout(r, 2000))
}
```
```python Python
import json

# 5. Poll for the browser's pending device request and approve it
for _ in range(30):
try:
res = sandbox.commands.run(
f"openclaw devices list --json --url ws://127.0.0.1:{PORT} --token {TOKEN}"
)
data = json.loads(res.stdout)
if data.get("pending"):
rid = data["pending"][0]["requestId"]
sandbox.commands.run(
f"openclaw devices approve {rid} --token {TOKEN} --url ws://127.0.0.1:{PORT}"
)
print(f"Device approved: {rid}")
break
except Exception:
pass
time.sleep(2)
```
</CodeGroup>

Once approved, the browser connects and the gateway UI loads.

## How it works

| Step | What happens |
|------|-------------|
| `--bind lan` | Gateway listens on `0.0.0.0` so E2B can proxy it |
| `--auth token` | Requires `?token=` on the URL for HTTP and WebSocket auth |
| Browser opens URL | Gateway serves the UI, browser opens a WebSocket |
| `code=1008 pairing required` | Gateway closes the WebSocket until the device is approved (secure mode only) |
| `devices approve` | Approves the browser's device fingerprint (secure mode only) |
| Browser reconnects | WebSocket connects successfully, UI is live |

## Gateway flags reference

| Flag | Purpose |
|------|---------|
| `--allow-unconfigured` | Start without a full config file |
| `--bind lan` | Bind to `0.0.0.0` (required for E2B port proxying) |

Check warning on line 150 in docs/agents/openclaw/openclaw-gateway.mdx

View check run for this annotation

Mintlify / Mintlify Validation (e2b) - vale-spellcheck

docs/agents/openclaw/openclaw-gateway.mdx#L150

Did you really mean 'proxying'?
| `--auth token` | Enable token-based authentication |
| `--token <value>` | The auth token (passed as `?token=` in the URL) |
| `--port <number>` | Gateway listen port (default: `18789`) |

## How to restart the gateway

Use this when the gateway is already running and you want a clean restart (for example, after changing model or env settings).

<Info>
We can't use the `openclaw gateway restart` command here. Some SDK environments cannot target a specific Unix user in `commands.run`. The commands below use the default command user context.
</Info>

<CodeGroup>
```typescript JavaScript & TypeScript
const TOKEN = process.env.OPENCLAW_APP_TOKEN || 'my-gateway-token'
const PORT = 18789

// 1) Kill existing gateway processes if present
await sandbox.commands.run(
`bash -lc 'for p in "[o]penclaw gateway" "[o]penclaw-gateway"; do for pid in $(pgrep -f "$p" || true); do kill "$pid" >/dev/null 2>&1 || true; done; done'`
)
await new Promise((r) => setTimeout(r, 1000))

// 2) Start gateway again
await sandbox.commands.run(
`openclaw gateway --allow-unconfigured --bind lan --auth token --token ${TOKEN} --port ${PORT}`,
{ background: true }
)

// 3) Wait for listening socket
for (let i = 0; i < 45; i++) {
const probe = await sandbox.commands.run(
`bash -lc 'ss -ltn | grep -q ":${PORT} " && echo ready || echo waiting'`
)
if (probe.stdout.trim() === 'ready') break
await new Promise((r) => setTimeout(r, 1000))
}
```
```python Python
import os, time

TOKEN = os.environ.get("OPENCLAW_APP_TOKEN", "my-gateway-token")
PORT = 18789

# 1) Kill existing gateway processes if present
sandbox.commands.run(
"""bash -lc 'for p in "[o]penclaw gateway" "[o]penclaw-gateway"; do
for pid in $(pgrep -f "$p" || true); do
kill "$pid" >/dev/null 2>&1 || true
done
done'"""
)
time.sleep(1)

# 2) Start gateway again
sandbox.commands.run(
f"openclaw gateway --allow-unconfigured --bind lan --auth token --token {TOKEN} --port {PORT}",
background=True,
)

# 3) Wait for listening socket
for _ in range(45):
probe = sandbox.commands.run(
f'bash -lc \'ss -ltn | grep -q ":{PORT} " && echo ready || echo waiting\''
)
if probe.stdout.strip() == "ready":
break
time.sleep(1)
```
</CodeGroup>

## Turn insecure flags off (recommended after testing)

Use this to restore secure device authentication after initial testing.

<CodeGroup>
```typescript JavaScript & TypeScript
const TOKEN = process.env.OPENCLAW_APP_TOKEN || 'my-gateway-token'
const PORT = 18789

await sandbox.commands.run(
`bash -lc 'openclaw config set gateway.controlUi.allowInsecureAuth false && ` +
`openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth false'`
)

await sandbox.commands.run(
`bash -lc 'for p in "[o]penclaw gateway" "[o]penclaw-gateway"; do for pid in $(pgrep -f "$p" || true); do kill "$pid" >/dev/null 2>&1 || true; done; done'`
)

await sandbox.commands.run(
`openclaw gateway --allow-unconfigured --bind lan --auth token --token ${TOKEN} --port ${PORT}`,
{ background: true }
)
```
```python Python
import os

TOKEN = os.environ.get("OPENCLAW_APP_TOKEN", "my-gateway-token")
PORT = 18789

sandbox.commands.run(
"bash -lc 'openclaw config set gateway.controlUi.allowInsecureAuth false && "
"openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth false'"
)

sandbox.commands.run(
"""bash -lc 'for p in "[o]penclaw gateway" "[o]penclaw-gateway"; do
for pid in $(pgrep -f "$p" || true); do
kill "$pid" >/dev/null 2>&1 || true
done
done'"""
)

sandbox.commands.run(
f"openclaw gateway --allow-unconfigured --bind lan --auth token --token {TOKEN} --port {PORT}",
background=True,
)
```
</CodeGroup>

## Related

<CardGroup cols={1}>
<Card title="OpenClaw Telegram" icon="message-circle" href="/docs/agents/openclaw/openclaw-telegram">
Connect OpenClaw to Telegram and approve pairing
</Card>
</CardGroup>
Loading