OpenClawSkills
GitHub
Gateway / Operations β€’ TutorialHeader.readTime

Remote Access

Remote access via SSH tunnels (Gateway WS) and tailnet.

This repository supports "remote over SSH" by running a single gateway (primary server) on a dedicated host (desktop/server), with clients connecting to it.

- For operators (you/macOS app): SSH tunneling is the universal fallback.

- For nodes (iOS/Android and future devices): connect to the gateway WebSocket (using LAN/tailnet or SSH tunnel as needed).

Tutorial.step

Core idea

- The gateway WebSocket binds to loopback on a configured port (default 18789).

- For remote use, you can forward that loopback port via SSH (or use tailnet/VPN to reduce tunnels).

Tutorial.step

Common VPN/tailnet setup (where the agent lives)

Think of the gateway host as "where the agent lives." It has sessions, auth profiles, channels, and state.

Laptops/desktops (and nodes) connect to that host.

#

Tutorial.step

1) Always-online gateway in tailnet (VPS or home server)

Run the gateway on a persistent host and access via Tailscale or SSH.

- ''Best UX:'' keep ''gateway.bind: "loopback"'' and use ''Tailscale Serve'' for the control UI.

- Fallback: maintain loopback + SSH tunnel from machines that need access.

- ''Examples:'' ''exe.dev'' (simple VM) or ''Hetzner'' (production VPS).

Great if your laptop sleeps often but you want the agent always online.

#

Tutorial.step

2) Run gateway on home desktop, remote control from laptop

The laptop does not run the agent. It connects remotely:

- Use the macOS app's Remote over SSH mode (Settings β†’ General β†’ "Where OpenClaw runs").

- The app opens and manages the tunnel so WebChat + health checks "just work."

Runbook: ''macOS remote access''.

#

Tutorial.step

3) Run gateway on laptop, remote access from other machines

Keep the gateway local but expose it safely:

- SSH tunnel from other machines to the laptop, or

- Tailscale serve for control UI and loopback-only gateway.

Guide: ''Tailscale'' and ''network overview''.

Tutorial.step

Command flow (what runs where)

A single gateway service owns state + channels. Nodes are peripherals.

Example flow (Telegram β†’ node):

- Telegram message arrives at the gateway.

- Gateway runs the agent, decides whether to invoke node tools.

- Gateway invokes the ''node'' via gateway WebSocket (''node.*'' RPC).

- Node returns result. Gateway replies to Telegram.

Note:

- ''Nodes do not run the gateway service.'' One gateway per host unless you deliberately run isolated profiles (see ''multiple gateways'').

- The macOS app "node mode" is just a node client on the gateway WebSocket.

Tutorial.step

SSH tunnel (CLI + tools)

Create a local tunnel to a remote gateway WS:

Bash
ssh -N -L 18789:127.0.0.1:18789 user@host

Once the tunnel is established:

- ''openclaw health'' and ''openclaw status --deep'' reach the remote gateway via ''ws://127.0.0.1:18789''.

- openclaw gateway {status,health,send,agent,call}' can also target the forwarded URL via --url if needed.

Note: Replace ''18789'' with your configured ''gateway.port'' (or ''--port''/''OPENCLAW_GATEWAY_PORT'').

Tutorial.step

CLI remote defaults

You can persist a remote target for CLI commands to use by default:

Json5
{
  gateway: {
    mode: "remote",
    remote: {
      url: "ws://127.0.0.1:18789",
      token: "your-token",
    },
  },
}

If the gateway is loopback-only, keep the URL as ''ws://127.0.0.1:18789'' and open the SSH tunnel first.

Tutorial.step

Chat UI over SSH

WebChat no longer uses a separate HTTP port. The SwiftUI chat UI connects directly to the gateway WebSocket.

- Forward ''18789'' via SSH (see above), then connect the client to ''ws://127.0.0.1:18789''.

- On macOS, prefer the app's "Remote over SSH" mode which manages the tunnel automatically.

Tutorial.step

macOS app "Remote over SSH"

The macOS menu bar app can drive the same setup end-to-end (remote health checks, WebChat, voice wake forwarding).

Runbook: ''macOS remote access''.

Tutorial.step

Security rules (remote/VPN)

TL;DR: keep the gateway loopback-only unless you need to bind otherwise.

- Loopback + SSH/Tailscale Serve is the safest default (no public exposure).

- ''Non-loopback binding'' (''lan''/''tailnet''/''custom'' or ''auto'' when loopback isn't available) requires auth token/password.

- ''gateway.remote.token'' is for remote CLI calls ''only'' β€” it doesn't enable local auth.

- If using ''wss://'', ''gateway.remote.tlsFingerprint'' pins the remote TLS certificate.

- ''Tailscale Serve'' can authenticate via identity headers if ''gateway.auth.allowTailscale: true''.

Set to ''false'' if you want token/password auth required.

- Treat browser control as operator access: tailnet-only + intentional node pairing.

Details: ''Security''.