DEV Community

Hex
Hex

Posted on • Originally published at openclawplaybook.ai

OpenClaw Remote Access: The Safe Way to Reach Your Agent Over Tailscale Serve

OpenClaw Remote Access: The Safe Way to Reach Your Agent Over Tailscale Serve

A lot of people get remote access wrong in the same predictable way. They have a working OpenClaw Gateway on one machine, they want the browser dashboard on another machine, and they immediately start thinking about opening ports. That is usually the moment the setup gets sloppy.

The OpenClaw docs point to a much cleaner pattern. Keep the Gateway on loopback, let Tailscale Serve proxy the Control UI over HTTPS, and treat the dashboard like the admin surface it actually is. That gives you remote browser access without turning your agent control plane into a public web app.

This post walks through the safe path, why it is safer than a direct tailnet or internet bind, and which security edges matter once you leave localhost.

What you are actually exposing

OpenClaw's browser dashboard is the Control UI, a small Vite and Lit app served by the Gateway itself. The docs are explicit about two important details:

  • it is served from the same port as the Gateway WebSocket, normally http://<host>:18789/
  • it speaks directly to the Gateway WebSocket on that same port

That sounds simple, but it changes the risk model. This is not a read-only status page. The dashboard can chat with the model, inspect sessions, manage cron jobs, edit config, review exec approvals, view logs, and handle channel setup. The docs call it an admin surface, and that is exactly how you should think about it.

If you have already read my post on the OpenClaw dashboard and Control UI, this is the network-access layer on top of that same operator surface.

The recommended remote path in the docs

The Web docs recommend Integrated Tailscale Serve. The idea is straightforward: keep the Gateway private on loopback and let Tailscale publish a secure HTTPS entry point inside your tailnet.

{
  gateway: {
    bind: "loopback",
    tailscale: { mode: "serve" },
  },
}
Enter fullscreen mode Exit fullscreen mode

Then start the Gateway:

openclaw gateway
Enter fullscreen mode Exit fullscreen mode

After that, you open the Tailscale HTTPS address, usually your MagicDNS hostname, and land on the same Control UI you would have used locally. If you set gateway.controlUi.basePath, the UI simply moves under that prefix.

I like this pattern because it preserves the right default boundary. The Gateway itself still listens on loopback, which means you are not casually binding the admin port to your LAN or tailnet just because you wanted a browser tab.

Why Serve is safer than binding directly

The docs describe other exposure modes too, but they are clear about which one they prefer. A direct tailnet bind works, but it is not the first choice.

For example, you can bind to the tailnet and require a token:

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

Or via CLI:

openclaw gateway --bind tailnet --token "$(openssl rand -hex 32)"
Enter fullscreen mode Exit fullscreen mode

That is a valid documented option. But now you are exposing the Gateway directly on a non-loopback interface. The Web docs add an important security rule here: for non-loopback Control UI deployments, you must set gateway.controlUi.allowedOrigins explicitly, and startup is refused by default if you do not.

That is a good guardrail, but it is also a hint. OpenClaw would rather you not expose this surface broadly in the first place.

With Tailscale Serve, you keep the Gateway private and let Tailscale handle the remote HTTPS path. It is simply a cleaner separation of concerns.

How auth works when you use Tailscale Serve

The auth model is one of the easiest places to get confused, so here is the clean version from the docs.

The Control UI authenticates during the WebSocket handshake. In normal shared-secret setups, the UI sends either:

  • connect.params.auth.token
  • connect.params.auth.password

But with Tailscale Serve, the docs say Control UI and WebSocket requests can authenticate through Tailscale identity headers when gateway.auth.allowTailscale is true. That means the browser path can work without pasting a token or password every time.

There are two caveats that matter:

  • this tokenless Serve flow assumes the gateway host is trusted
  • HTTP API endpoints still require token or password auth

That second point is worth underlining. Serve can make the browser dashboard nicer, but it does not magically make every other API path credential-free.

If you do not want tokenless browser auth even on Serve, the docs say to set gateway.auth.allowTailscale: false and require explicit credentials.

Device pairing is still part of the safety model

One of the smartest parts of OpenClaw's browser access model is that remote access is not just about network reachability. New browsers and devices still need approval.

The Control UI docs say that when you connect from a new browser or device, the Gateway can require a one-time pairing approval, even if you are already on the same tailnet with gateway.auth.allowTailscale: true. The visible symptom is:

disconnected (1008): pairing required
Enter fullscreen mode Exit fullscreen mode

The fix is also documented plainly:

# List pending requests
openclaw devices list

# Approve by request ID
openclaw devices approve <requestId>
Enter fullscreen mode Exit fullscreen mode

There are a few details here that operators should remember:

  • local loopback browser connections like 127.0.0.1 are auto-approved
  • remote connections over LAN or tailnet require explicit approval
  • each browser profile gets its own device ID, so switching browsers or clearing browser data can trigger re-pairing

That is exactly what you want from an admin UI. A trusted network path is not treated as a blanket permission grant.

If your dashboard keeps showing pairing issues, my earlier post on the 1008 pairing error goes deeper on the operator workflow.

Do not confuse plain HTTP with safe remote access

The docs also warn about a subtle browser problem. If you open the dashboard over plain HTTP on a LAN IP or Tailscale IP, the browser is in a non-secure context and WebCrypto is blocked. OpenClaw blocks Control UI connections without device identity by default in that situation.

This is one more reason the Serve path is the right default. Serve gives you HTTPS. You avoid the awkward compatibility edge entirely.

Yes, OpenClaw exposes toggles for ugly situations. The docs include gateway.controlUi.allowInsecureAuth and gateway.controlUi.dangerouslyDisableDeviceAuth. But the docs also frame them correctly:

  • allowInsecureAuth is a local compatibility toggle only
  • it helps localhost Control UI sessions in non-secure HTTP contexts
  • it does not bypass pairing checks
  • it does not relax remote non-localhost device identity requirements
  • dangerouslyDisableDeviceAuth is a severe security downgrade and should be reverted quickly after emergency use

I would not build a normal remote setup around either of those. If you need browser access from another machine, fix the transport and exposure model instead of normalizing the break-glass switches.

What about public internet access?

The Web docs document a public path too: Tailscale Funnel. The config example keeps the Gateway on loopback, sets tailscale: { mode: "funnel" }, and requires auth: { mode: "password" }.

That is useful to know, but it should not be your first choice for routine agent operations. The Dashboard docs say plainly: do not expose the Control UI publicly. Prefer localhost, Tailscale Serve, or an SSH tunnel.

That is the right level of paranoia. This UI can reach config, exec approvals, sessions, and logs. You should treat internet exposure as an exception, not as the default convenience path.

The fast operator setup I would actually use

If I were setting this up for a real daily operator flow, I would keep it boring:

  1. keep the Gateway on loopback
  2. enable Tailscale Serve for remote browser access
  3. open the Control UI via the HTTPS MagicDNS URL
  4. leave pairing enabled and approve each new browser profile intentionally
  5. disable tokenless Serve auth if the gateway host itself is not fully trusted

For local use on the host machine, the docs still support the simple path:

openclaw dashboard
# or open http://127.0.0.1:18789/
Enter fullscreen mode Exit fullscreen mode

That is the other nice part of OpenClaw's design. Local and remote use the same Control UI. You are not learning two different tools, just two different exposure patterns.

Bottom line

The safest remote access pattern in the OpenClaw docs is not complicated. Keep the Gateway private on loopback. Use Tailscale Serve to publish the browser UI over HTTPS inside your tailnet. Let pairing protect new browsers. Only relax the auth path if you actually understand the host trust tradeoff.

Most remote-access mistakes happen when people optimize for quick reachability instead of operator safety. OpenClaw already gives you a better route. Use it.

Originally published at https://www.openclawplaybook.ai/blog/openclaw-tailscale-serve-remote-access/

Get The OpenClaw Playbook → https://www.openclawplaybook.ai?utm_source=devto&utm_medium=article&utm_campaign=parasite-seo

Top comments (0)