{
  "title": "Bonjour / mDNS discovery",
  "content": "OpenClaw uses Bonjour (mDNS / DNS‑SD) as a **LAN‑only convenience** to discover\nan active Gateway (WebSocket endpoint). It is best‑effort and does **not** replace SSH or\nTailnet-based connectivity.\n\n## Wide‑area Bonjour (Unicast DNS‑SD) over Tailscale\n\nIf the node and gateway are on different networks, multicast mDNS won’t cross the\nboundary. You can keep the same discovery UX by switching to **unicast DNS‑SD**\n(\"Wide‑Area Bonjour\") over Tailscale.\n\n1. Run a DNS server on the gateway host (reachable over Tailnet).\n2. Publish DNS‑SD records for `_openclaw-gw._tcp` under a dedicated zone\n   (example: `openclaw.internal.`).\n3. Configure Tailscale **split DNS** so your chosen domain resolves via that\n   DNS server for clients (including iOS).\n\nOpenClaw supports any discovery domain; `openclaw.internal.` is just an example.\niOS/Android nodes browse both `local.` and your configured wide‑area domain.\n\n### Gateway config (recommended)\n\n### One‑time DNS server setup (gateway host)\n\nThis installs CoreDNS and configures it to:\n\n* listen on port 53 only on the gateway’s Tailscale interfaces\n* serve your chosen domain (example: `openclaw.internal.`) from `~/.openclaw/dns/<domain>.db`\n\nValidate from a tailnet‑connected machine:\n\n### Tailscale DNS settings\n\nIn the Tailscale admin console:\n\n* Add a nameserver pointing at the gateway’s tailnet IP (UDP/TCP 53).\n* Add split DNS so your discovery domain uses that nameserver.\n\nOnce clients accept tailnet DNS, iOS nodes can browse\n`_openclaw-gw._tcp` in your discovery domain without multicast.\n\n### Gateway listener security (recommended)\n\nThe Gateway WS port (default `18789`) binds to loopback by default. For LAN/tailnet\naccess, bind explicitly and keep auth enabled.\n\nFor tailnet‑only setups:\n\n* Set `gateway.bind: \"tailnet\"` in `~/.openclaw/openclaw.json`.\n* Restart the Gateway (or restart the macOS menubar app).\n\nOnly the Gateway advertises `_openclaw-gw._tcp`.\n\n* `_openclaw-gw._tcp` — gateway transport beacon (used by macOS/iOS/Android nodes).\n\n## TXT keys (non‑secret hints)\n\nThe Gateway advertises small non‑secret hints to make UI flows convenient:\n\n* `role=gateway`\n* `displayName=<friendly name>`\n* `lanHost=<hostname>.local`\n* `gatewayPort=<port>` (Gateway WS + HTTP)\n* `gatewayTls=1` (only when TLS is enabled)\n* `gatewayTlsSha256=<sha256>` (only when TLS is enabled and fingerprint is available)\n* `canvasPort=<port>` (only when the canvas host is enabled; default `18793`)\n* `sshPort=<port>` (defaults to 22 when not overridden)\n* `transport=gateway`\n* `cliPath=<path>` (optional; absolute path to a runnable `openclaw` entrypoint)\n* `tailnetDns=<magicdns>` (optional hint when Tailnet is available)\n\n## Debugging on macOS\n\nUseful built‑in tools:\n\n* Browse instances:\n  \n* Resolve one instance (replace `<instance>`):\n\nIf browsing works but resolving fails, you’re usually hitting a LAN policy or\nmDNS resolver issue.\n\n## Debugging in Gateway logs\n\nThe Gateway writes a rolling log file (printed on startup as\n`gateway log file: ...`). Look for `bonjour:` lines, especially:\n\n* `bonjour: advertise failed ...`\n* `bonjour: ... name conflict resolved` / `hostname conflict resolved`\n* `bonjour: watchdog detected non-announced service ...`\n\n## Debugging on iOS node\n\nThe iOS node uses `NWBrowser` to discover `_openclaw-gw._tcp`.\n\n* Settings → Gateway → Advanced → **Discovery Debug Logs**\n* Settings → Gateway → Advanced → **Discovery Logs** → reproduce → **Copy**\n\nThe log includes browser state transitions and result‑set changes.\n\n## Common failure modes\n\n* **Bonjour doesn’t cross networks**: use Tailnet or SSH.\n* **Multicast blocked**: some Wi‑Fi networks disable mDNS.\n* **Sleep / interface churn**: macOS may temporarily drop mDNS results; retry.\n* **Browse works but resolve fails**: keep machine names simple (avoid emojis or\n  punctuation), then restart the Gateway. The service instance name derives from\n  the host name, so overly complex names can confuse some resolvers.\n\n## Escaped instance names (`\\032`)\n\nBonjour/DNS‑SD often escapes bytes in service instance names as decimal `\\DDD`\nsequences (e.g. spaces become `\\032`).\n\n* This is normal at the protocol level.\n* UIs should decode for display (iOS uses `BonjourEscapes.decode`).\n\n## Disabling / configuration\n\n* `OPENCLAW_DISABLE_BONJOUR=1` disables advertising (legacy: `OPENCLAW_DISABLE_BONJOUR`).\n* `gateway.bind` in `~/.openclaw/openclaw.json` controls the Gateway bind mode.\n* `OPENCLAW_SSH_PORT` overrides the SSH port advertised in TXT (legacy: `OPENCLAW_SSH_PORT`).\n* `OPENCLAW_TAILNET_DNS` publishes a MagicDNS hint in TXT (legacy: `OPENCLAW_TAILNET_DNS`).\n* `OPENCLAW_CLI_PATH` overrides the advertised CLI path (legacy: `OPENCLAW_CLI_PATH`).\n\n* Discovery policy and transport selection: [Discovery](/gateway/discovery)\n* Node pairing + approvals: [Gateway pairing](/gateway/pairing)",
  "code_samples": [
    {
      "code": "### One‑time DNS server setup (gateway host)",
      "language": "unknown"
    },
    {
      "code": "This installs CoreDNS and configures it to:\n\n* listen on port 53 only on the gateway’s Tailscale interfaces\n* serve your chosen domain (example: `openclaw.internal.`) from `~/.openclaw/dns/<domain>.db`\n\nValidate from a tailnet‑connected machine:",
      "language": "unknown"
    },
    {
      "code": "### Tailscale DNS settings\n\nIn the Tailscale admin console:\n\n* Add a nameserver pointing at the gateway’s tailnet IP (UDP/TCP 53).\n* Add split DNS so your discovery domain uses that nameserver.\n\nOnce clients accept tailnet DNS, iOS nodes can browse\n`_openclaw-gw._tcp` in your discovery domain without multicast.\n\n### Gateway listener security (recommended)\n\nThe Gateway WS port (default `18789`) binds to loopback by default. For LAN/tailnet\naccess, bind explicitly and keep auth enabled.\n\nFor tailnet‑only setups:\n\n* Set `gateway.bind: \"tailnet\"` in `~/.openclaw/openclaw.json`.\n* Restart the Gateway (or restart the macOS menubar app).\n\n## What advertises\n\nOnly the Gateway advertises `_openclaw-gw._tcp`.\n\n## Service types\n\n* `_openclaw-gw._tcp` — gateway transport beacon (used by macOS/iOS/Android nodes).\n\n## TXT keys (non‑secret hints)\n\nThe Gateway advertises small non‑secret hints to make UI flows convenient:\n\n* `role=gateway`\n* `displayName=<friendly name>`\n* `lanHost=<hostname>.local`\n* `gatewayPort=<port>` (Gateway WS + HTTP)\n* `gatewayTls=1` (only when TLS is enabled)\n* `gatewayTlsSha256=<sha256>` (only when TLS is enabled and fingerprint is available)\n* `canvasPort=<port>` (only when the canvas host is enabled; default `18793`)\n* `sshPort=<port>` (defaults to 22 when not overridden)\n* `transport=gateway`\n* `cliPath=<path>` (optional; absolute path to a runnable `openclaw` entrypoint)\n* `tailnetDns=<magicdns>` (optional hint when Tailnet is available)\n\n## Debugging on macOS\n\nUseful built‑in tools:\n\n* Browse instances:",
      "language": "unknown"
    },
    {
      "code": "* Resolve one instance (replace `<instance>`):",
      "language": "unknown"
    }
  ],
  "headings": [
    {
      "level": "h2",
      "text": "Wide‑area Bonjour (Unicast DNS‑SD) over Tailscale",
      "id": "wide‑area-bonjour-(unicast-dns‑sd)-over-tailscale"
    },
    {
      "level": "h3",
      "text": "Gateway config (recommended)",
      "id": "gateway-config-(recommended)"
    },
    {
      "level": "h3",
      "text": "One‑time DNS server setup (gateway host)",
      "id": "one‑time-dns-server-setup-(gateway-host)"
    },
    {
      "level": "h3",
      "text": "Tailscale DNS settings",
      "id": "tailscale-dns-settings"
    },
    {
      "level": "h3",
      "text": "Gateway listener security (recommended)",
      "id": "gateway-listener-security-(recommended)"
    },
    {
      "level": "h2",
      "text": "What advertises",
      "id": "what-advertises"
    },
    {
      "level": "h2",
      "text": "Service types",
      "id": "service-types"
    },
    {
      "level": "h2",
      "text": "TXT keys (non‑secret hints)",
      "id": "txt-keys-(non‑secret-hints)"
    },
    {
      "level": "h2",
      "text": "Debugging on macOS",
      "id": "debugging-on-macos"
    },
    {
      "level": "h2",
      "text": "Debugging in Gateway logs",
      "id": "debugging-in-gateway-logs"
    },
    {
      "level": "h2",
      "text": "Debugging on iOS node",
      "id": "debugging-on-ios-node"
    },
    {
      "level": "h2",
      "text": "Common failure modes",
      "id": "common-failure-modes"
    },
    {
      "level": "h2",
      "text": "Escaped instance names (`\\032`)",
      "id": "escaped-instance-names-(`\\032`)"
    },
    {
      "level": "h2",
      "text": "Disabling / configuration",
      "id": "disabling-/-configuration"
    },
    {
      "level": "h2",
      "text": "Related docs",
      "id": "related-docs"
    }
  ],
  "url": "llms-txt#bonjour-/-mdns-discovery",
  "links": []
}