{ "title": "Web (Gateway)", "content": "The Gateway serves a small **browser Control UI** (Vite + Lit) from the same port as the Gateway WebSocket:\n\n* default: `http://:18789/`\n* optional prefix: set `gateway.controlUi.basePath` (e.g. `/openclaw`)\n\nCapabilities live in [Control UI](/web/control-ui).\nThis page focuses on bind modes, security, and web-facing surfaces.\n\nWhen `hooks.enabled=true`, the Gateway also exposes a small webhook endpoint on the same HTTP server.\nSee [Gateway configuration](/gateway/configuration) → `hooks` for auth + payloads.\n\n## Config (default-on)\n\nThe Control UI is **enabled by default** when assets are present (`dist/control-ui`).\nYou can control it via config:\n\n### Integrated Serve (recommended)\n\nKeep the Gateway on loopback and let Tailscale Serve proxy it:\n\nThen start the gateway:\n\n* `https:///` (or your configured `gateway.controlUi.basePath`)\n\n### Tailnet bind + token\n\nThen start the gateway (token required for non-loopback binds):\n\n* `http://:18789/` (or your configured `gateway.controlUi.basePath`)\n\n### Public internet (Funnel)\n\n* Gateway auth is required by default (token/password or Tailscale identity headers).\n* Non-loopback binds still **require** a shared token/password (`gateway.auth` or env).\n* The wizard generates a gateway token by default (even on loopback).\n* The UI sends `connect.params.auth.token` or `connect.params.auth.password`.\n* The Control UI sends anti-clickjacking headers and only accepts same-origin browser\n websocket connections unless `gateway.controlUi.allowedOrigins` is set.\n* With Serve, Tailscale identity headers can satisfy auth when\n `gateway.auth.allowTailscale` is `true` (no token/password required). Set\n `gateway.auth.allowTailscale: false` to require explicit credentials. See\n [Tailscale](/gateway/tailscale) and [Security](/gateway/security).\n* `gateway.tailscale.mode: \"funnel\"` requires `gateway.auth.mode: \"password\"` (shared password).\n\nThe Gateway serves static files from `dist/control-ui`. Build them with:", "code_samples": [ { "code": "## Tailscale access\n\n### Integrated Serve (recommended)\n\nKeep the Gateway on loopback and let Tailscale Serve proxy it:", "language": "unknown" }, { "code": "Then start the gateway:", "language": "unknown" }, { "code": "Open:\n\n* `https:///` (or your configured `gateway.controlUi.basePath`)\n\n### Tailnet bind + token", "language": "unknown" }, { "code": "Then start the gateway (token required for non-loopback binds):", "language": "unknown" }, { "code": "Open:\n\n* `http://:18789/` (or your configured `gateway.controlUi.basePath`)\n\n### Public internet (Funnel)", "language": "unknown" }, { "code": "## Security notes\n\n* Gateway auth is required by default (token/password or Tailscale identity headers).\n* Non-loopback binds still **require** a shared token/password (`gateway.auth` or env).\n* The wizard generates a gateway token by default (even on loopback).\n* The UI sends `connect.params.auth.token` or `connect.params.auth.password`.\n* The Control UI sends anti-clickjacking headers and only accepts same-origin browser\n websocket connections unless `gateway.controlUi.allowedOrigins` is set.\n* With Serve, Tailscale identity headers can satisfy auth when\n `gateway.auth.allowTailscale` is `true` (no token/password required). Set\n `gateway.auth.allowTailscale: false` to require explicit credentials. See\n [Tailscale](/gateway/tailscale) and [Security](/gateway/security).\n* `gateway.tailscale.mode: \"funnel\"` requires `gateway.auth.mode: \"password\"` (shared password).\n\n## Building the UI\n\nThe Gateway serves static files from `dist/control-ui`. Build them with:", "language": "unknown" } ], "headings": [ { "level": "h2", "text": "Webhooks", "id": "webhooks" }, { "level": "h2", "text": "Config (default-on)", "id": "config-(default-on)" }, { "level": "h2", "text": "Tailscale access", "id": "tailscale-access" }, { "level": "h3", "text": "Integrated Serve (recommended)", "id": "integrated-serve-(recommended)" }, { "level": "h3", "text": "Tailnet bind + token", "id": "tailnet-bind-+-token" }, { "level": "h3", "text": "Public internet (Funnel)", "id": "public-internet-(funnel)" }, { "level": "h2", "text": "Security notes", "id": "security-notes" }, { "level": "h2", "text": "Building the UI", "id": "building-the-ui" } ], "url": "llms-txt#web-(gateway)", "links": [] }