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 to 127.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 to 0.0.0.0 if Tailscale automation is enabled.
  • "custom" – Allows binding to an explicit address specified in gateway.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 by gateway.bind.
  • "serve" – Keeps the gateway bound to 127.0.0.1 while Tailscale creates an HTTPS proxy via tailscale serve, making the service accessible only within your Tailnet.
  • "funnel" – Uses tailscale funnel to 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 the ClosedClaw_GATEWAY_TOKEN environment variable is present, the system defaults to this mode.
  • mode: "password" – Uses a shared secret string. Required when using tailscale.mode: "funnel".
  • allowTailscale: true – When combined with tailscale.mode: "serve", clients can authenticate via Tailscale identity headers instead of presenting a token or password. The gateway validates these headers against tailscale whois data in src/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, and auto, defined in src/config/zod-schema.ts.
  • Tailscale integration offers three tiers: disabled (off), Tailnet-only HTTPS (serve), and public internet (funnel), implemented in src/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.serve with allowTailscale: 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 gateway CLI, 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →