How to Configure ClosedClaw Gateway Exposure: Local, LAN, Tailscale, and Public Access Options
ClosedClaw supports five distinct gateway exposure modes—loopback, LAN, direct Tailnet, Tailscale Serve, and Tailscale Funnel—controlled via the gateway.bind and gateway.tailscale.mode configuration fields defined in src/config/zod-schema.ts.
The ClosedClaw gateway serves as the central WebSocket server that all UI clients (Web, TUI, desktop, and Chrome extension) and node-hosts connect to. The asafelobotomy/closedclaw repository exposes network accessibility through a strict configuration schema, allowing you to bind the server to specific interfaces or proxy through Tailscale for secure remote access.
Gateway Bind Modes
The gateway.bind field in src/config/zod-schema.ts (lines 3009–3015) accepts five string values that determine which network interface the WebSocket listener binds to:
"loopback"– Binds exclusively to127.0.0.1, restricting access to the local machine only."lan"– Discovers and binds to the host’s LAN IP address (e.g.,192.168.x.x), allowing other devices on the same network to connect."tailnet"– Binds directly to the machine’s Tailscale IP (e.g.,100.x.x.x) without using Tailscale Serve or Funnel, exposing the service only to your Tailnet."auto"– Defaults to loopback, but falls back to0.0.0.0if Tailscale automation is enabled."custom"– Allows binding to an explicit address specified ingateway.customBindHost.
When the gateway starts, src/gateway/server-startup.ts reads the resolved configuration and instantiates the GatewayServer on the address dictated by this setting.
Tailscale Integration Modes
The gateway.tailscale.mode field (defined in src/config/zod-schema.ts lines 3036–3040) automates Tailscale tunneling for the Control UI and WebSocket endpoint:
"off"– Disables Tailscale automation; the gateway listens directly on the interface determined bygateway.bind."serve"– Keeps the gateway bound to127.0.0.1while Tailscale creates an HTTPS proxy viatailscale serve, making the service accessible only within your Tailnet."funnel"– Usestailscale funnelto expose a public HTTPS endpoint on the internet. This mode requires password-based authentication (gateway.auth.mode: "password").
The Tailscale helper logic in src/infra/tailscale.ts executes the appropriate CLI commands during server startup and handles cleanup on exit.
Authentication Requirements
The gateway.auth object (lines 3026–3033) controls how clients authenticate to the gateway:
mode: "token"– Uses a random secret token. When theClosedClaw_GATEWAY_TOKENenvironment variable is present, the system defaults to this mode.mode: "password"– Uses a shared secret string. Required when usingtailscale.mode: "funnel".allowTailscale: true– When combined withtailscale.mode: "serve", clients can authenticate via Tailscale identity headers instead of presenting a token or password. The gateway validates these headers againsttailscale whoisdata insrc/gateway/protocol/auth.ts.
Remote Gateway Mode
For scenarios where the UI runs on a different machine than the gateway process, the gateway.remote object (lines 3044–3050) configures the local instance to act as a client bridge:
{
"gateway": {
"remote": {
"url": "ssh://user@host:22",
"transport": "ssh",
"token": "my-gateway-token",
"sshIdentity": "~/.ssh/id_ed25519"
}
}
}
This setting makes the local process forward client traffic to a remote gateway endpoint while preserving authentication handling.
Configuration Examples
Local Development (Loopback Only)
For single-machine development where only local clients connect:
{
"gateway": {
"bind": "loopback",
"auth": { "mode": "token" }
}
}
The UI connects to ws://127.0.0.1:18789.
LAN Network Sharing
To allow other devices on your private network to access the gateway:
{
"gateway": {
"bind": "lan",
"auth": { "mode": "token" }
}
}
CLI shortcut:
ClosedClaw gateway --bind lan
Direct Tailnet Binding
Expose the gateway directly on your Tailscale IP without HTTPS proxying:
{
"gateway": {
"bind": "tailnet",
"auth": {
"mode": "token",
"token": "my-secret"
}
}
}
Connect from another Tailnet device:
ClosedClaw tui --url ws://100.123.45.67:18789 --token my-secret
Tailscale Serve (Tailnet HTTPS)
Secure your gateway with HTTPS within your Tailnet only:
{
"gateway": {
"bind": "loopback",
"tailscale": { "mode": "serve" },
"auth": {
"mode": "token",
"allowTailscale": true
}
}
}
The Control UI becomes reachable at https://<magic-dns>/ using Tailscale identity headers for authentication.
Tailscale Funnel (Public Internet)
Expose the dashboard publicly with password protection:
{
"gateway": {
"bind": "loopback",
"tailscale": { "mode": "funnel" },
"auth": {
"mode": "password",
"password": "replace-me"
}
}
}
CLI command:
ClosedClaw gateway --tailscale funnel --auth password
Remote Gateway via SSH
Run the UI locally while the gateway process operates on a remote headless server:
{
"gateway": {
"mode": "remote",
"remote": {
"url": "ssh://user@host:22",
"token": "my-gateway-token"
}
}
}
Implementation Architecture
During startup, src/gateway/server-startup.ts resolves the configuration (including wizard overrides from src/wizard/onboarding.gateway-config.ts) and initializes the GatewayServer. If gateway.tailscale.mode is active, src/infra/tailscale.ts establishes the tunnel before the WebSocket listener starts.
When clients connect, src/gateway/protocol/auth.ts validates credentials against the gateway.auth schema. For Tailscale Serve with allowTailscale: true, the system inspects x-forwarded-for and x-forwarded-proto headers to verify the Tailnet node identity before accepting the connection.
Summary
- Five bind modes control network exposure:
loopback,lan,tailnet,custom, andauto, defined insrc/config/zod-schema.ts. - Tailscale integration offers three tiers: disabled (
off), Tailnet-only HTTPS (serve), and public internet (funnel), implemented insrc/infra/tailscale.ts. - Funnel mode requires password authentication; standard token auth is insufficient for public exposure.
- Tailnet identity authentication allows passwordless access when using
tailscale.servewithallowTailscale: true. - Remote gateway mode supports SSH tunneling for split UI/gateway architectures.
- All configuration changes can be applied via the onboarding wizard, the
ClosedClaw configure gatewayCLI, or direct edits to~/.ClosedClaw/ClosedClaw.json.
Frequently Asked Questions
What is the default gateway exposure mode in ClosedClaw?
The default configuration uses gateway.bind: "auto", which prefers loopback (127.0.0.1) for security. If Tailscale automation is detected during startup, it falls back to 0.0.0.0 to accommodate the proxy, though the service remains protected by your Tailnet ACLs.
Can I use token authentication with Tailscale Funnel?
No. The tailscale.mode: "funnel" configuration explicitly requires gateway.auth.mode: "password" because the endpoint is exposed to the public internet. Token-based authentication is permitted for loopback, lan, and tailnet bindings, as well as tailscale.serve when combined with Tailscale identity verification.
How does ClosedClaw validate Tailscale identity headers?
When allowTailscale: true is set alongside tailscale.mode: "serve", the authentication handler in src/gateway/protocol/auth.ts inspects incoming requests for Tailscale-specific headers. It executes tailscale whois to verify that the connecting node belongs to your Tailnet, bypassing the token/password requirement only for verified Tailscale identities.
What port does the ClosedClaw gateway use?
The gateway listens on port 18789 by default for WebSocket connections. This port is used across all bind modes, though the accessibility depends on your gateway.bind setting—whether bound to localhost, LAN, Tailscale IP, or proxied through Tailscale Serve/Funnel on standard HTTPS ports.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →