{
  "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://<host>: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://<magicdns>/` (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://<tailscale-ip>: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://<magicdns>/` (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://<tailscale-ip>: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": []
}