Gateway Web Surfaces: Control UI, Bind Modes, and Security

This page covers the Gateway's browser-based Control UI, bind modes, webhooks, and Admin HTTP RPC. It is intended for administrators configuring web-facing features and security.

Read this when

  • You want to access the Gateway over Tailscale
  • You want the browser Control UI and config editing

The Gateway hosts a compact browser-based Control UI (built with Vite and Lit) on the same port used by the Gateway WebSocket:

  • default: http://<host>:18789/
  • with gateway.tls.enabled: true: https://<host>:18789/
  • optional prefix: configure gateway.controlUi.basePath (for example /openclaw)

All capabilities are documented in the Control UI. This page describes bind modes, security, and other web-facing features.

Config (default-on)

Control UI is active by default whenever the asset files are present (dist/control-ui):

{
  gateway: {
    controlUi: { enabled: true, basePath: "/openclaw" }, // basePath optional
  },
}

Webhooks

If hooks.enabled=true is set, the Gateway also provides a webhook endpoint on that same HTTP server. Refer to hooks in the Gateway configuration reference for authentication details and payload formats.

Admin HTTP RPC

POST /api/v1/admin/rpc makes selected Gateway control-plane methods available over HTTP. It is disabled by default and only registers when the admin-http-rpc plugin is active. For the authentication model, supported methods, and a comparison with the WebSocket API, see Admin HTTP RPC.

Tailscale access

Integrated Serve (recommended)

Bind the Gateway to loopback and let Tailscale Serve handle proxying:

{
  gateway: {
    bind: "loopback",
    tailscale: { mode: "serve" },
  },
}

Launch the gateway:

openclaw gateway

Navigate to https://<magicdns>/ (or whatever gateway.controlUi.basePath you have set).

Tailnet bind with token

{
  gateway: {
    bind: "tailnet",
    controlUi: { enabled: true },
    auth: { mode: "token", token: "your-token" },
  },
}

Start the gateway (this example binds to a non-loopback address and uses shared-secret token authentication):

openclaw gateway

Open http://<tailscale-ip>:18789/ (or your configured gateway.controlUi.basePath).

Public internet (Funnel)

{
  gateway: {
    bind: "loopback",
    tailscale: { mode: "funnel" },
    auth: { mode: "password" }, // or OPENCLAW_GATEWAY_PASSWORD
  },
}

tailscale.mode: "funnel" requires gateway.auth.mode: "password"; both Serve and Funnel need gateway.bind: "loopback".

Security notes

  • Gateway authentication is enforced by default, using a token, password, trusted-proxy header, or Tailscale Serve identity headers when that feature is turned on.
  • Non-loopback binds still require gateway authentication: either token/password auth or an identity-aware reverse proxy with gateway.auth.mode: "trusted-proxy".
  • The onboarding wizard sets up shared-secret authentication by default and typically creates a gateway token, even on loopback.
  • In shared-secret mode, the UI transmits connect.params.auth.token or connect.params.auth.password during the WebSocket handshake.
  • When gateway.tls.enabled: true is active, local dashboard and status helpers display https:// URLs and wss:// WebSocket URLs.
  • In identity-bearing modes (Tailscale Serve, trusted-proxy), the WebSocket authentication check is satisfied from request headers rather than a shared secret.
  • For public non-loopback Control UI deployments, set gateway.controlUi.allowedOrigins explicitly (full origins). Private same-origin loads are accepted without it for loopback, RFC1918/link-local, .local, .ts.net, and Tailscale CGNAT hosts.
  • gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback: true enables Host-header origin fallback; this is a dangerous security downgrade.
  • With Serve, Tailscale identity headers satisfy Control UI and WebSocket authentication when gateway.auth.allowTailscale: true (no token or password needed). HTTP API endpoints do not use Tailscale identity headers; they always follow the gateway's normal HTTP auth mode. Set gateway.auth.allowTailscale: false to require explicit credentials even over Serve. This tokenless flow assumes the gateway host itself is trusted. See Tailscale and Security.

Building the UI

The Gateway serves static files from dist/control-ui:

pnpm ui:build