diff --git a/SECURITY.md b/SECURITY.md index 6cf5fc61de..f4ccac868c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -60,6 +60,7 @@ OpenClaw's web interface (Gateway Control UI + HTTP endpoints) is intended for * - CLI: `openclaw gateway run --bind loopback`. - Do **not** expose it to the public internet (no direct bind to `0.0.0.0`, no public reverse proxy). It is not hardened for public exposure. - If you need remote access, prefer an SSH tunnel or Tailscale serve/funnel (so the Gateway still binds to loopback), plus strong Gateway auth. +- The Gateway HTTP surface includes the canvas host (`/__openclaw__/canvas/`, `/__openclaw__/a2ui/`). Treat canvas content as sensitive/untrusted and avoid exposing it beyond loopback unless you understand the risk. ## Runtime Requirements diff --git a/docs/concepts/architecture.md b/docs/concepts/architecture.md index 24e1fb69f7..de9582c714 100644 --- a/docs/concepts/architecture.md +++ b/docs/concepts/architecture.md @@ -19,7 +19,10 @@ Last updated: 2026-01-22 - **Nodes** (macOS/iOS/Android/headless) also connect over **WebSocket**, but declare `role: node` with explicit caps/commands. - One Gateway per host; it is the only place that opens a WhatsApp session. -- A **canvas host** (default `18793`) serves agent‑editable HTML and A2UI. +- The **canvas host** is served by the Gateway HTTP server under: + - `/__openclaw__/canvas/` (agent-editable HTML/CSS/JS) + - `/__openclaw__/a2ui/` (A2UI host) + It uses the same port as the Gateway (default `18789`). ## Components and flows diff --git a/docs/gateway/bonjour.md b/docs/gateway/bonjour.md index 9e2ad8753a..608d3b11ab 100644 --- a/docs/gateway/bonjour.md +++ b/docs/gateway/bonjour.md @@ -94,7 +94,7 @@ The Gateway advertises small non‑secret hints to make UI flows convenient: - `gatewayPort=` (Gateway WS + HTTP) - `gatewayTls=1` (only when TLS is enabled) - `gatewayTlsSha256=` (only when TLS is enabled and fingerprint is available) -- `canvasPort=` (only when the canvas host is enabled; default `18793`) +- `canvasPort=` (only when the canvas host is enabled; currently the same as `gatewayPort`) - `sshPort=` (defaults to 22 when not overridden) - `transport=gateway` - `cliPath=` (optional; absolute path to a runnable `openclaw` entrypoint) diff --git a/docs/gateway/configuration-reference.md b/docs/gateway/configuration-reference.md index 4f3a339807..008d15ff46 100644 --- a/docs/gateway/configuration-reference.md +++ b/docs/gateway/configuration-reference.md @@ -2065,14 +2065,18 @@ Auth: `Authorization: Bearer ` or `x-openclaw-token: `. { canvasHost: { root: "~/.openclaw/workspace/canvas", - port: 18793, liveReload: true, // enabled: false, // or OPENCLAW_SKIP_CANVAS_HOST=1 }, } ``` -- Serves HTML/CSS/JS over HTTP for iOS/Android nodes. +- Serves agent-editable HTML/CSS/JS and A2UI over HTTP under the Gateway port: + - `http://:/__openclaw__/canvas/` + - `http://:/__openclaw__/a2ui/` +- Local-only: keep `gateway.bind: "loopback"` (default). +- Non-loopback binds: canvas routes require Gateway auth (token/password/trusted-proxy), same as other Gateway HTTP surfaces. +- Node WebViews typically don't send auth headers; after a node is paired and connected, the Gateway allows a private-IP fallback so the node can load canvas/A2UI without leaking secrets into URLs. - Injects live-reload client into served HTML. - Auto-creates starter `index.html` when empty. - Also serves A2UI at `/__openclaw__/a2ui/`. diff --git a/docs/gateway/discovery.md b/docs/gateway/discovery.md index 644bd7b196..6212df61e0 100644 --- a/docs/gateway/discovery.md +++ b/docs/gateway/discovery.md @@ -64,7 +64,7 @@ Troubleshooting and beacon details: [Bonjour](/gateway/bonjour). - `gatewayPort=18789` (Gateway WS + HTTP) - `gatewayTls=1` (only when TLS is enabled) - `gatewayTlsSha256=` (only when TLS is enabled and fingerprint is available) - - `canvasPort=18793` (default canvas host port; serves `/__openclaw__/canvas/`) + - `canvasPort=` (canvas host port; currently the same as `gatewayPort` when the canvas host is enabled) - `cliPath=` (optional; absolute path to a runnable `openclaw` entrypoint or binary) - `tailnetDns=` (optional hint; auto-detected when Tailscale is available) diff --git a/docs/gateway/multiple-gateways.md b/docs/gateway/multiple-gateways.md index 5bc641e1cf..d6f35e08a4 100644 --- a/docs/gateway/multiple-gateways.md +++ b/docs/gateway/multiple-gateways.md @@ -79,7 +79,7 @@ openclaw --profile rescue gateway install Base port = `gateway.port` (or `OPENCLAW_GATEWAY_PORT` / `--port`). - browser control service port = base + 2 (loopback only) -- `canvasHost.port = base + 4` +- canvas host is served on the Gateway HTTP server (same port as `gateway.port`) - Browser profile CDP ports auto-allocate from `browser.controlPort + 9 .. + 108` If you override any of these in config or env, you must keep them unique per instance. diff --git a/docs/gateway/network-model.md b/docs/gateway/network-model.md index 1cbd6a99b3..c7f65aa22d 100644 --- a/docs/gateway/network-model.md +++ b/docs/gateway/network-model.md @@ -13,5 +13,8 @@ process that owns channel connections and the WebSocket control plane. - One Gateway per host is recommended. It is the only process allowed to own the WhatsApp Web session. For rescue bots or strict isolation, run multiple gateways with isolated profiles and ports. See [Multiple gateways](/gateway/multiple-gateways). - Loopback first: the Gateway WS defaults to `ws://127.0.0.1:18789`. The wizard generates a gateway token by default, even for loopback. For tailnet access, run `openclaw gateway --bind tailnet --token ...` because tokens are required for non-loopback binds. - Nodes connect to the Gateway WS over LAN, tailnet, or SSH as needed. The legacy TCP bridge is deprecated. -- Canvas host is an HTTP file server on `canvasHost.port` (default `18793`) serving `/__openclaw__/canvas/` for node WebViews. See [Gateway configuration](/gateway/configuration) (`canvasHost`). +- Canvas host is served by the Gateway HTTP server on the **same port** as the Gateway (default `18789`): + - `/__openclaw__/canvas/` + - `/__openclaw__/a2ui/` + When `gateway.auth` is configured and the Gateway binds beyond loopback, these routes are protected by Gateway auth (loopback requests are exempt). See [Gateway configuration](/gateway/configuration) (`canvasHost`, `gateway`). - Remote use is typically SSH tunnel or tailnet VPN. See [Remote access](/gateway/remote) and [Discovery](/gateway/discovery). diff --git a/docs/gateway/security/index.md b/docs/gateway/security/index.md index d4644d713c..9f8f831f14 100644 --- a/docs/gateway/security/index.md +++ b/docs/gateway/security/index.md @@ -347,6 +347,16 @@ The Gateway multiplexes **WebSocket + HTTP** on a single port: - Default: `18789` - Config/flags/env: `gateway.port`, `--port`, `OPENCLAW_GATEWAY_PORT` +This HTTP surface includes the Control UI and the canvas host: + +- Control UI (SPA assets) (default base path `/`) +- Canvas host: `/__openclaw__/canvas/` and `/__openclaw__/a2ui/` (arbitrary HTML/JS; treat as untrusted content) + +If you load canvas content in a normal browser, treat it like any other untrusted web page: + +- Don't expose the canvas host to untrusted networks/users. +- Don't make canvas content share the same origin as privileged web surfaces unless you fully understand the implications. + Bind mode controls where the Gateway listens: - `gateway.bind: "loopback"` (default): only local clients can connect. diff --git a/docs/install/gcp.md b/docs/install/gcp.md index 6026fd87d5..b0ec51a75d 100644 --- a/docs/install/gcp.md +++ b/docs/install/gcp.md @@ -266,10 +266,6 @@ services: # Recommended: keep the Gateway loopback-only on the VM; access via SSH tunnel. # To expose it publicly, remove the `127.0.0.1:` prefix and firewall accordingly. - "127.0.0.1:${OPENCLAW_GATEWAY_PORT}:18789" - - # Optional: only if you run iOS/Android nodes against this VM and need Canvas host. - # If you expose this publicly, read /gateway/security and firewall accordingly. - # - "18793:18793" command: [ "node", diff --git a/docs/install/hetzner.md b/docs/install/hetzner.md index df8cbfbfdb..7ca46ff7cd 100644 --- a/docs/install/hetzner.md +++ b/docs/install/hetzner.md @@ -177,10 +177,6 @@ services: # Recommended: keep the Gateway loopback-only on the VPS; access via SSH tunnel. # To expose it publicly, remove the `127.0.0.1:` prefix and firewall accordingly. - "127.0.0.1:${OPENCLAW_GATEWAY_PORT}:18789" - - # Optional: only if you run iOS/Android nodes against this VPS and need Canvas host. - # If you expose this publicly, read /gateway/security and firewall accordingly. - # - "18793:18793" command: [ "node", diff --git a/docs/platforms/android.md b/docs/platforms/android.md index b786e1782e..39f5aa12ae 100644 --- a/docs/platforms/android.md +++ b/docs/platforms/android.md @@ -123,20 +123,20 @@ The Android node’s Chat sheet uses the gateway’s **primary session key** (`m If you want the node to show real HTML/CSS/JS that the agent can edit on disk, point the node at the Gateway canvas host. -Note: nodes use the standalone canvas host on `canvasHost.port` (default `18793`). +Note: nodes load canvas from the Gateway HTTP server (same port as `gateway.port`, default `18789`). 1. Create `~/.openclaw/workspace/canvas/index.html` on the gateway host. 2. Navigate the node to it (LAN): ```bash -openclaw nodes invoke --node "" --command canvas.navigate --params '{"url":"http://.local:18793/__openclaw__/canvas/"}' +openclaw nodes invoke --node "" --command canvas.navigate --params '{"url":"http://.local:18789/__openclaw__/canvas/"}' ``` -Tailnet (optional): if both devices are on Tailscale, use a MagicDNS name or tailnet IP instead of `.local`, e.g. `http://:18793/__openclaw__/canvas/`. +Tailnet (optional): if both devices are on Tailscale, use a MagicDNS name or tailnet IP instead of `.local`, e.g. `http://:18789/__openclaw__/canvas/`. This server injects a live-reload client into HTML and reloads on file changes. -The A2UI host lives at `http://:18793/__openclaw__/a2ui/`. +The A2UI host lives at `http://:18789/__openclaw__/a2ui/`. Canvas commands (foreground only): diff --git a/docs/platforms/ios.md b/docs/platforms/ios.md index b92a7e83bc..e56f7e192a 100644 --- a/docs/platforms/ios.md +++ b/docs/platforms/ios.md @@ -69,12 +69,13 @@ In Settings, enable **Manual Host** and enter the gateway host + port (default ` The iOS node renders a WKWebView canvas. Use `node.invoke` to drive it: ```bash -openclaw nodes invoke --node "iOS Node" --command canvas.navigate --params '{"url":"http://:18793/__openclaw__/canvas/"}' +openclaw nodes invoke --node "iOS Node" --command canvas.navigate --params '{"url":"http://:18789/__openclaw__/canvas/"}' ``` Notes: - The Gateway canvas host serves `/__openclaw__/canvas/` and `/__openclaw__/a2ui/`. +- It is served from the Gateway HTTP server (same port as `gateway.port`, default `18789`). - The iOS node auto-navigates to A2UI on connect when a canvas host URL is advertised. - Return to the built-in scaffold with `canvas.navigate` and `{"url":""}`. diff --git a/docs/platforms/mac/canvas.md b/docs/platforms/mac/canvas.md index 0475f0d4e2..d749896e7a 100644 --- a/docs/platforms/mac/canvas.md +++ b/docs/platforms/mac/canvas.md @@ -73,7 +73,7 @@ A2UI host page on first open. Default A2UI host URL: ``` -http://:18793/__openclaw__/a2ui/ +http://:18789/__openclaw__/a2ui/ ``` ### A2UI commands (v0.8)