{ "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/.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=`\n* `lanHost=.local`\n* `gatewayPort=` (Gateway WS + HTTP)\n* `gatewayTls=1` (only when TLS is enabled)\n* `gatewayTlsSha256=` (only when TLS is enabled and fingerprint is available)\n* `canvasPort=` (only when the canvas host is enabled; default `18793`)\n* `sshPort=` (defaults to 22 when not overridden)\n* `transport=gateway`\n* `cliPath=` (optional; absolute path to a runnable `openclaw` entrypoint)\n* `tailnetDns=` (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 ``):\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/.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=`\n* `lanHost=.local`\n* `gatewayPort=` (Gateway WS + HTTP)\n* `gatewayTls=1` (only when TLS is enabled)\n* `gatewayTlsSha256=` (only when TLS is enabled and fingerprint is available)\n* `canvasPort=` (only when the canvas host is enabled; default `18793`)\n* `sshPort=` (defaults to 22 when not overridden)\n* `transport=gateway`\n* `cliPath=` (optional; absolute path to a runnable `openclaw` entrypoint)\n* `tailnetDns=` (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 ``):", "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": [] }