{
  "title": "Remote OpenClaw (macOS ⇄ remote host)",
  "content": "This flow lets the macOS app act as a full remote control for a OpenClaw gateway running on another host (desktop/server). It’s the app’s **Remote over SSH** (remote run) feature. All features—health checks, Voice Wake forwarding, and Web Chat—reuse the same remote SSH configuration from *Settings → General*.\n\n* **Local (this Mac)**: Everything runs on the laptop. No SSH involved.\n* **Remote over SSH (default)**: OpenClaw commands are executed on the remote host. The mac app opens an SSH connection with `-o BatchMode` plus your chosen identity/key and a local port-forward.\n* **Remote direct (ws/wss)**: No SSH tunnel. The mac app connects to the gateway URL directly (for example, via Tailscale Serve or a public HTTPS reverse proxy).\n\nRemote mode supports two transports:\n\n* **SSH tunnel** (default): Uses `ssh -N -L ...` to forward the gateway port to localhost. The gateway will see the node’s IP as `127.0.0.1` because the tunnel is loopback.\n* **Direct (ws/wss)**: Connects straight to the gateway URL. The gateway sees the real client IP.\n\n## Prereqs on the remote host\n\n1. Install Node + pnpm and build/install the OpenClaw CLI (`pnpm install && pnpm build && pnpm link --global`).\n2. Ensure `openclaw` is on PATH for non-interactive shells (symlink into `/usr/local/bin` or `/opt/homebrew/bin` if needed).\n3. Open SSH with key auth. We recommend **Tailscale** IPs for stable reachability off-LAN.\n\n1. Open *Settings → General*.\n2. Under **OpenClaw runs**, pick **Remote over SSH** and set:\n   * **Transport**: **SSH tunnel** or **Direct (ws/wss)**.\n   * **SSH target**: `user@host` (optional `:port`).\n     * If the gateway is on the same LAN and advertises Bonjour, pick it from the discovered list to auto-fill this field.\n   * **Gateway URL** (Direct only): `wss://gateway.example.ts.net` (or `ws://...` for local/LAN).\n   * **Identity file** (advanced): path to your key.\n   * **Project root** (advanced): remote checkout path used for commands.\n   * **CLI path** (advanced): optional path to a runnable `openclaw` entrypoint/binary (auto-filled when advertised).\n3. Hit **Test remote**. Success indicates the remote `openclaw status --json` runs correctly. Failures usually mean PATH/CLI issues; exit 127 means the CLI isn’t found remotely.\n4. Health checks and Web Chat will now run through this SSH tunnel automatically.\n\n* **SSH tunnel**: Web Chat connects to the gateway over the forwarded WebSocket control port (default 18789).\n* **Direct (ws/wss)**: Web Chat connects straight to the configured gateway URL.\n* There is no separate WebChat HTTP server anymore.\n\n* The remote host needs the same TCC approvals as local (Automation, Accessibility, Screen Recording, Microphone, Speech Recognition, Notifications). Run onboarding on that machine to grant them once.\n* Nodes advertise their permission state via `node.list` / `node.describe` so agents know what’s available.\n\n* Prefer loopback binds on the remote host and connect via SSH or Tailscale.\n* If you bind the Gateway to a non-loopback interface, require token/password auth.\n* See [Security](/gateway/security) and [Tailscale](/gateway/tailscale).\n\n## WhatsApp login flow (remote)\n\n* Run `openclaw channels login --verbose` **on the remote host**. Scan the QR with WhatsApp on your phone.\n* Re-run login on that host if auth expires. Health check will surface link problems.\n\n* **exit 127 / not found**: `openclaw` isn’t on PATH for non-login shells. Add it to `/etc/paths`, your shell rc, or symlink into `/usr/local/bin`/`/opt/homebrew/bin`.\n* **Health probe failed**: check SSH reachability, PATH, and that Baileys is logged in (`openclaw status --json`).\n* **Web Chat stuck**: confirm the gateway is running on the remote host and the forwarded port matches the gateway WS port; the UI requires a healthy WS connection.\n* **Node IP shows 127.0.0.1**: expected with the SSH tunnel. Switch **Transport** to **Direct (ws/wss)** if you want the gateway to see the real client IP.\n* **Voice Wake**: trigger phrases are forwarded automatically in remote mode; no separate forwarder is needed.\n\n## Notification sounds\n\nPick sounds per notification from scripts with `openclaw` and `node.invoke`, e.g.:\n\nThere is no global “default sound” toggle in the app anymore; callers choose a sound (or none) per request.",
  "code_samples": [],
  "headings": [
    {
      "level": "h2",
      "text": "Modes",
      "id": "modes"
    },
    {
      "level": "h2",
      "text": "Remote transports",
      "id": "remote-transports"
    },
    {
      "level": "h2",
      "text": "Prereqs on the remote host",
      "id": "prereqs-on-the-remote-host"
    },
    {
      "level": "h2",
      "text": "macOS app setup",
      "id": "macos-app-setup"
    },
    {
      "level": "h2",
      "text": "Web Chat",
      "id": "web-chat"
    },
    {
      "level": "h2",
      "text": "Permissions",
      "id": "permissions"
    },
    {
      "level": "h2",
      "text": "Security notes",
      "id": "security-notes"
    },
    {
      "level": "h2",
      "text": "WhatsApp login flow (remote)",
      "id": "whatsapp-login-flow-(remote)"
    },
    {
      "level": "h2",
      "text": "Troubleshooting",
      "id": "troubleshooting"
    },
    {
      "level": "h2",
      "text": "Notification sounds",
      "id": "notification-sounds"
    }
  ],
  "url": "llms-txt#remote-openclaw-(macos-⇄-remote-host)",
  "links": []
}