Full Transcript
In this section, we will explore how to secure web interfaces used by gateway operators. Ensuring these interfaces are protected is critical to maintaining network integrity and preventing unauthorized access. In this section, we'll explore the control UI, a browser-based interface served by the gateway, and understand how it manages authentication. The control UI is a lightweight single-page application built with V and Lit. It runs in the browser and is served directly by the gateway, typically accessible at port 18789. You can also configure it to run under a different path to keep the UI and websocket connection under the same origin. Authentication happens during the websocket handshake. The gateway checks several sources of authentication information in a specific order to verify the connection. The gateway prioritizes authentication sources as follows. First, an explicit token or password. Second, a device token provided during handshake. Third, a stored device token recognized by the gateway. And lastly, a bootstrap token used for initial onboarding. If enabled, the gateway can also accept identity headers from Tailscale, serve, or trusted proxies as authentication sources. These still follow the same precedence rules we've just discussed. The control UI treats every browser profile as a separate device by generating a unique device ID. This means using different browsers, private windows, or clearing site data will require re-pairing since they appear as new devices. For security, new device connections must be approved once by an operator, even if they come from the same tailnet. The only exception is connection from localhost, which are auto-approved by default. Let's look at how to manage pending pairing requests using the CLI. You can list all pending requests and approve them by their request ID. This code shows two commands. One to list all pending device pairing requests, and another to approve a specific request by its ID. This process ensures only authorized devices gain access. Approving a pairing request consumes it. So, if the browser retries, it might generate a new request that also needs approval. The CLI output helps identify requests by showing IDs and device details. The control UI includes several configuration flags that can modify pairing and authentication behavior. These should be used carefully as operational overrides. Here is an example configuration snippet that sets the control UI to embed sandbox scripts, enhancing security by isolating embedded content. This JSON configures the gateway's control UI to use script-based embed sandboxing, which can help contain scripts within a secure environment. For development purposes, you can enable insecure authentication, but this is risky and should never be used in production environments. This JSON example enables insecure authentication by setting allow insecure off to true, while also configuring token-based authentication. Use this only in safe, controlled environments. You can completely disable device authentication, but this is very dangerous and should only be done in strictly controlled test environments. This JSON disables device authentication entirely by setting dangerously disable device off to true. This removes critical security protections and should be avoided in production. Disabling device authentication or allowing insecure off removes vital protections. Never expose the dashboard publicly if these are enabled. Instead, use local loopback, SSH tunnels, or tailscale serve for secure access. The control UI stores the active authentication token only in session storage for the current browser tab. It avoids keeping passwords or tokens in URLs or displaying them on the page, enhancing security. On first load, the control UI detects the browser's locale and loads translations for supported languages on demand. Missing translations default to English, keeping the initial load small. If you encounter an unauthorized 1008 error when connecting via websocket, here are some troubleshooting steps to resolve common causes. First, verify that the gateway is reachable at the expected address. If accessing remotely, consider using an SSH tunnel instead of exposing the UI directly. Check that the token or password used for authentication matches the configured value in the gateway settings or secret ref, ensuring credentials are correct. Make sure the device attempting to connect has been approved. Use the CLI to list and approve any pending pairing requests as needed. When using tailscale serve, verify that allow tailscale is enabled and that identity headers are properly forwarded to the gateway for authentication. As a recovery step, establish an SSH local port forwarding tunnel to connect via localhost. This can bypass network or proxy header problems interfering with authentication. Treat the control UI as an administrative interface. Keep it accessible only via loopback, SSH tunnels, or authenticated proxies. Avoid disabling device authentication except in tightly controlled test environments. In this section, we'll explore the administrative dashboard focusing on safe access patterns and recovery methods. Understanding how to securely manage and recover the dashboard is crucial for maintaining control. The control UI acts as an admin console allowing you to view sessions, adjust configurations, approve executions, and manage devices. Because of this sensitivity, you should never expose the dashboard directly to the public internet without a clear secure access plan. Let's review the recommended hosting patterns for the dashboard prioritized by security and convenience. First, keep the gateway bound to the loopback interface. Access the dashboard locally or via SSH tunnels to avoid exposing it externally. Second, use SSH tunnels to forward the gateway port remotely. This method prevents the dashboard from being exposed over public HTTP. Third, Tailscale service recommended for remote access. It proxies the dashboard while keeping the gateway loopback bound eliminating the need for a public port. Only bind the dashboard to a public interface after hardening it with token or password authentication, strict allowed origins, and disabling risky fallback flags. The gateway serves the built control UI from the same HTTP server and port used for websocket connections typically at port 18789. The UI must be built and enabled in the configuration before it's available. Developers must run the build command PNPM UI build to generate the UI assets in dist/control UI which the gateway then serves. For local development, the dev server can open a URL that includes the gateway token in a URL fragment for one-time bootstrap authentication. Here is an example URL format used during development to connect to the gateway with a token supplied in the fragment. When a client connects via web socket, the gateway checks authentication in this order: shared token or password, explicit device token, stored device token from approval, and finally a one-time bootstrap token. The open claw dashboard command prints a non-tokenized URL and can auto open a local link to avoid accidentally exposing sensitive tokens in shell history or clipboard. To allow a development UI origin to connect, add its URL to the allowed origins list in your gateway JSON configuration. This snippet shows how to permit the localhost development server origin in the gateway configuration. You can explicitly enable the control UI and configure a base path in the gateway settings to customize the URL where the UI is served. This example enables the control UI and sets the base path to {slash} open claw in the gateway configuration. Here is a configuration snippet showing how to bind the gateway to a tailscale tailnet with token authentication and the control UI enabled. This JSON config binds the gateway to the tailnet, enables the control UI, and sets token-based authentication with a specified token. Never enable flags like dangerously host header origin fallback or dangerously disable device off in production. These disable important security checks and increase risk. If you use tailscale funnel mode, the gateway must use password authentication. You could supply the password via environment variables like open claw underscore password. If you encounter a 1008 unauthorized error, start by verifying the gateway is reachable locally or via SSH tunnel. Then retrieve the auth token, check allowed origins and base path, and ensure the gateway is not bound non-loopback without proper configuration. Here's a concise checklist for operators to maintain secure and a functional dashboard access. Always prefer keeping the gateway bound to the loopback interface to minimize exposure. Make sure to build the UI assets before enabling the control UI to avoid serving an incomplete interface. If the UI is accessible beyond loopback, explicitly set allowed origins to restrict which domains can connect. For remote access, rely on SSH tunnels or Tailscale serve to avoid exposing the dashboard publicly. Avoid enabling host header fallback options in production as they weaken origin checks and increase security risks. Following these rules and recovery steps ensures the control UI remains accessible for operators while protecting sensitive admin functions from accidental exposure. In this section, we'll explore the terminal user interface or TUI, focusing on its behavior, commands, and ergonomic features. You'll learn how to start and connect the TUI, manage sessions, and use key command effectively. Before launching the TUI, ensure the gateway is running on the host you want to connect to. The gateway listens for websocket clients like the control UI, web chat, and TUI, so it must be reachable first. You can start the gateway by running a simple command in your shell. This activates the gateway process that the TUI will connect to. This command launches the gateway service. Keep this running before starting your TUI client. Once the gateway is running, start the TUI client on your local machine to begin interacting with it. This command starts the TUI client locally, connecting to the gateway on the same host by default. To connect the TUI to a remote gateway, specify the websocket URL and provide the gateway token for authentication. This command connects your TUI client to a remote gateway using the specified websocket URL and token for secure access. If your gateway uses password authentication, use the password flag instead of token. The TUI registers itself as mode 2A and will notify you on reconnects with session status messages. Let's look at how sessions are scoped and how history is managed within the TUI environment. Each agent is identified by unique slug. Sessions belong to an agent and use a namespaced key format. This helps the gateway manage runs, transcripts, and permissions per agent. When you connect, the TUI fetches recent chat history from the gateway, typically the last 200 messages, and streams assistant responses live until completion. By default, messages you send to the gateway do not get delivered to upstream model providers. This safe by default setting prevents accidental usage and costs. You must explicitly enable delivery either via commands or toggles in the TUI footer to allow message forwarding to providers. You can enable delivery for your session by running the local command {slash} deliver on or using the delivery option in the TUI settings menu. Alternatively, start the TUI with the deliver flag to enable delivery for that session from the start. The TUI interface includes a header, chat log, status line, and input editor. The footer shows connection state, selected agent, session key, model, token counts, and delivery status. Always check the footer before sending messages. Lines starting with {exclamation point} execute local shell commands after you approve a one-time prompt. A lone {exclamation point} is treated as chat text. Use local exec cautiously, as it can modify files and should only be used on trusted hosts. Tool calls appear as cards in the chat log with arguments and results. Partial outputs stream live into the card. Use {control + O} to expand or collapse tool outputs during streaming. The TUI offers several keyboard shortcuts to improve workflow efficiency. Let's review the most useful ones. Press enter to send your current input message. Use escape to abort the current running process or response. {Control + C} clears your input line. Pressing it twice will exit the TUI. {Control + D} immediately exits the TUI client. These shortcuts open various pickers or toggle views. Notably, {control + O} toggles the expansion of tool output cards. The TUI auto detects your terminal's foreground color for assistant text. You can override the theme by uh setting an environment variable before launching. Set this environment variable to force the TUI to use a light theme. Set this environment variable to force the TUI to use a dark theme. Be cautious when sharing your terminal session. Local exec and tool outputs may expose sensitive data, so only enable these features on trusted hosts and networks. To summarize, first, ensure the gateway is running. Then, start the TUI locally or remotely. Check the footer for correct settings, enable delivery when ready, and approve local exec before using shell commands. In this section, we'll explore how to serve the control UI alongside the gateway, understand different bind modes, and integrate with Tailscale for secure access. The gateway can serve the browser-based control UI from the same HTTP server that handles its WebSocket API. This happens when the UI assets are built and enabled, typically accessible at port 18789 unless a custom base path is set. Before the gateway can serve the control UI, you must build it using the command pnpm UI build from the source workspace. If the dist/control UI directory exists, the gateway will enable the UI by default unless you disable it explicitly. Here's a simple JSON snippet to enable the control UI and set a static base path in your gateway configuration. This helps customize where the UI is served. This configuration enables the control UI and sets the base path to /openclaw. This means the UI will be accessible at that path on the gateway's HTTP server. If webhook support is enabled, the gateway exposes webhook endpoints on the same HTTP server. It's important to review authentication options and payload contracts before enabling webhooks on non-loopback binds for security. Let's review guidance on choosing the appropriate bind mode for your gateway deployment based on your environment and access needs. For local development or single-machine setups, bind the gateway to loopback. This keeps the service local and reduces attack surface. Use Tailscale serve if you want to expose the UI externally without changing the spot. When you need the gateway accessible within your private Tailscale network, bind the tailnet. Ensure you enforce token or password authentication and explicitly configure allowed origins for security. Avoid exposing the gateway directly to the public internet. If necessary, use Tailscale funnel or reverse proxy with strict CORS and authentication to protect access. The recommended approach is to keep the gateway bound to loopback and use Tailscale serve or funnel to proxy external connections. This maintains a safe default bind while allowing secure external access. Here's an example configuration where the gateway binds to loopback and Tailscale is set to serve mode, enabling external access through Tailscale without exposing the gateway directly. This JSON config binds the gateway to loopback and enables Tailscale serve mode. This setup keeps the gateway local while allowing Tailscale to handle external requests securely. For internal access within a Tailscale tailnet, bind the gateway to tailnet and enable token-based authentication to secure access from other machines on your private network. This configuration binds the gateway to the tailnet, enables the control UI, and secures access with a token. Replace your token with a secure shared secret. Tailscale funnel mode exposes the gateway to the public internet but requires password authentication. You can set the password in the config or via an environment variable for security. This config keeps the gateway on loopback, enables funnel mode for public exposure, and requires password authentication to protect access. Let's cover important security rules and warnings to keep your gateway safe when configuring bind modes and authentication. Any bind mode other than loopback must have authentication enabled such as token, password, or trusted proxy. The onboarding wizard usually generates a shared secret token. Keep it secure. Always set allowed origins when binding to non-loopback interfaces. Without this, the gateway will refuse to start for public or non-local deployments to prevent unauthorized access. Do not enable dangerously host header origin fallback unless you fully understand the risks. This setting weakens security by allowing host header spoofing which can be exploited. Here are the main configuration keys operators typically adjust to customize gateway behavior and security. The gateway.bind key controls the network interface the gateway listens on such as loopback for local only, Tailnet for private network, or 0.0.0.0 for all interfaces. The gateway.tailscale.mode setting controls how Tailscale integrates with options to serve the UI, expose via funnel, or disable integration. Authentication mode is set by gateway.auth.mode choosing between token, password, or trusted proxy methods to secure access. Control UI settings include enabling the UI, setting a base path, and defining allowed origins for secure web access. Webhook support is controlled by gateway.hooks.enabled and related authentication options to secure webhook endpoints. Operationally, always set allowed origins and prefer using Tailscale serve or reverse proxy. This keeps the gateway loopback bound while safely exposing the UI externally. In this section, we'll explore how the native SwiftUI web chat client interacts with the gateway using key APIs. We'll cover how history is managed and the special role of chat.inject for adding a native SwiftUI chat client for macOS and iOS that connects directly to the gateway via web socket. It primarily uses three APIs. chat.history to fetch conversation history, chat.send to post user messages, and chat.inject to add entries without triggering agent runs. The gateway normalizes history before sending it to web chat. This display normalization removes internal control tags, XML payloads for tool calls, and silent tokens like ino_reply entries, ensuring users see a clean conversation. The full transcript with all details remains stored for debugging. The chat.inject API appends assistant notes directly into the transcript without triggering an agent run. This is useful for operator annotations or system messages that should appear in the conversation but not cause follow-up reasoning or tool calls. For example, injecting a note about refreshed external data. History returned by chat.history is truncated to a bounded window and display normalized. If a client needs older entries for debugging or continuity, it can request an expanded range. The control UI and CLI provide controls to fetch these older transcript pages. The control UI's tools panel distinguishes between runtime availability and configuration. Available right now shows what tools the agent can call at the moment, while tool configuration displays the full catalog and profile overrides. When the gateway is unreachable, web chat becomes read-only since send and inject require a live web socket connection. In this section, we'll cover how to build and run the control UI, which is a small V and lit single page app served by the gateway. You'll learn the common developer workflow steps for both development and production. The control UI is served from the gateway's HTTP and web socket port. For local testing, you typically open a browser at localhost on port 18789. The main workflow involves running the UI in development mode, building a production bundle, and configuring the gateway if hosting under a path prefix. During development, run the UI in dev mode to see your code changes live. The dev server runs on V's default port and requires specifying the gateway web socket URL using the gateway URL query parameter. Use this command to start the development server for the control UI. It enables live reloading and debugging as you modify the UI code. Open the dev UI in your browser at this URL, replacing gateway host with your gateway's address. This connects the UI to the gateway's web socket endpoint for real-time communication. For initial setup, you can include a gateway token in a URL fragment. The dashboard removes tokens from the visible URL after loading to prevent accidental exposure. When ready to deploy, build the UI and its static assets. These go into the dist/control UI directory for where the gateway will serve them directly. Run this command to create the optimized production build of the control UI. This prepares the files for deployment. If you host the UI under a path prefix like /openclaw, set the openclaw_control_ui_path environment variable at build time. Then configure the gateway to use the same base path, so asset URLs resolve correctly. This example shows how to set the base path environment variable inline when building the UI. It ensures all asset URLs include the prefix /openclaw. Let's review some important operational tips and common troubleshooting steps to help you avoid issues when running the control UI. If these paths don't match, the UI won't load its resources correctly, causing failures. Always keep them in sync. When running the dev server, add its origin to the gateway's allowed origins list to pass CORS and authentication origin checks. Make sure the websocket URL is accessible from the UI host machine. If connection fails, check the gateway status and logs for errors. It's best to build assets during deployment or on the host machine to keep the repository size small and avoid unnecessary commits. In this section, we'll cover essential command line recipes for managing device pairing, starting the gateway safely, and accessing recovery tools. These commands assume you have local shell access and the gateway installed. It's helpful to maintain a concise cheat sheet for quick triage tasks. This includes listing and approving pending pairing requests, starting the gateway with secure access, and connecting to a remote terminal UI for recovery. When a browser or node appears as pending, you can list all pending pairing requests and approve a specific one by its request ID. This is done from the host controlling the gateway. Here are the commands. First, list all pending device pairing requests with openclaw devices list. then approve a specific request using open claw devices approve followed by the request ID. This lets you control which devices connect. Remember, pairing and device approval are covered in detail elsewhere. Always verify the source of a pairing request before approving it to maintain security. To start the gateway for local use, simply run it without extra options. By default, it binds to the loopback interface, which is useful before opening the control UI or terminal UI. This command starts the gateway bound to the local loopback interface, ensuring it is accessible only from the host machine. Instead of binding the gateway to a public interface, use tailscale serve. This keeps the gateway bound to loopback while securely proxying traffic, reducing exposure. This command starts the gateway with tailscale serve enabled, providing secure external access without exposing the gateway directly to the network. For more details on tailscale patterns and gateway authorization, refer to the hosting section and the gateway.auth.allowtailscale configuration. You can bind the gateway to your tailnet using an inline generated token. This is handy for automated scripts and produces a random hexadecimal token for secure binding. This command starts the gateway bound to the tailnet with a freshly generated 32-byte hex token, ensuring a secure and unique connection token each time. The terminal UI can be opened locally, connecting to the gateway web socket on loopback, or remotely by specifying connection details. This provides recovery access and command-line control. This command launches the terminal UI locally, connecting to the gateway on a loopback interface for direct access. To connect the terminal UI to a remote gateway, provide the websocket URL and the gateway token. This enables remote recovery or management sessions. This command connects the terminal UI to a remote gateway by specifying the websocket URL and the authentication token, enabling secure remote access. Note that message delivery to upstream providers is disabled by default. You must enable it via the settings toggle or by passing the deliver flag when sending messages. Never paste long-lived tokens in public shells, logs, or shared pastebins. For safety, prefer SSH tunnels or tailscale server instead of binding the gateway to a public IP address.