Bonjour Discovery for OpenClaw Gateway

Learn how OpenClaw uses Bonjour/mDNS to find gateways, including LAN and wide-area setup, and how to debug common discovery failures. Essential for gateway operators and network administrators.

Read this when

  • Debugging Bonjour discovery issues on macOS/iOS
  • Changing mDNS service types, TXT records, or discovery UX

OpenClaw leverages Bonjour (mDNS/DNS-SD) to locate an active gateway, which is a WebSocket endpoint. Multicast local. browsing serves as a LAN-only convenience: the bundled bonjour plugin handles LAN advertising, launching automatically on macOS hosts while requiring opt-in on Linux, Windows, and containerized gateway deployments. The same beacon can additionally broadcast through a configured wide-area DNS-SD domain, enabling discovery across networks. This discovery mechanism operates on a best-effort basis and does not substitute for SSH or Tailnet-based connectivity.

Wide-area Bonjour (Unicast DNS-SD) over Tailscale

When the node and gateway reside on separate networks, multicast mDNS cannot traverse the boundary. To preserve the same discovery experience, switch to unicast DNS-SD ("Wide-Area Bonjour") over Tailscale:

  1. Deploy a DNS server on the gateway host that is reachable via the Tailnet.
  2. Advertise DNS-SD records for _openclaw-gw._tcp within a dedicated zone, for instance openclaw.internal..
  3. Set up Tailscale split DNS so your chosen domain resolves through that DNS server for clients, iOS included.

The openclaw.internal. reference above serves only as an illustration, OpenClaw accommodates any discovery domain. iOS and Android nodes browse both local. and your configured wide-area domain.

Gateway config

{
  gateway: { bind: "tailnet" }, // tailnet-only (recommended)
  discovery: { wideArea: { domain: "openclaw.internal" } },
}

Configuring discovery.wideArea.domain turns on wide-area discovery. As a fallback when the config key remains unset, OpenClaw also recognizes the OPENCLAW_WIDE_AREA_DOMAIN environment variable.

One-time DNS server setup (gateway host, macOS only)

openclaw dns setup --apply

This command works exclusively on macOS and depends on Homebrew plus an active Tailscale connection. It installs CoreDNS (brew install coredns) and sets it up to:

  • listen on port 53 solely on the gateway's Tailscale interfaces
  • serve your designated domain (example: openclaw.internal.) from ~/.openclaw/dns/<domain>.db

Execute it without --apply first to see the plan (domain, zone file path, detected Tailnet IP, recommended config) without installing anything.

Verify from a machine connected to the Tailnet:

dns-sd -B _openclaw-gw._tcp openclaw.internal.
dig @<TAILNET_IPV4> -p 53 _openclaw-gw._tcp.openclaw.internal PTR +short

Tailscale DNS settings

Within the Tailscale admin console:

  • Register a nameserver pointing to the gateway's Tailnet IP (UDP/TCP 53).
  • Configure split DNS so your discovery domain relies on that nameserver.

After clients adopt Tailnet DNS, iOS nodes and CLI discovery can browse _openclaw-gw._tcp in your discovery domain without relying on multicast.

Gateway listener security

By default, the gateway WS port (default 18789) binds to loopback. For LAN or Tailnet access, bind explicitly while keeping auth enabled. For Tailnet-only configurations, assign gateway.bind: "tailnet" in ~/.openclaw/openclaw.json and restart the gateway (or the macOS menubar app).

What advertises

Only the gateway advertises _openclaw-gw._tcp. LAN multicast advertising originates from the bundled bonjour plugin when activated; wide-area DNS-SD publishing remains under gateway control.

Service types

  • _openclaw-gw._tcp serves as the gateway transport beacon, utilized by macOS/iOS/Android nodes.

TXT keys (non-secret hints)

KeyWhen present
role=gatewayAlways.
displayName=<friendly name>Always.
lanHost=<hostname>.localAlways.
gatewayPort=<port>Always (gateway WS + HTTP).
transport=gatewayAlways.
gatewayTls=1Only when TLS is enabled.
gatewayTlsSha256=<sha256>Only when TLS is enabled and a fingerprint is available.
gatewayDirectReachable=1Only when the gateway is directly reachable (not only via a relay/proxy path).
tailnetDns=<magicdns>mDNS full mode only; optional hint when Tailnet is available.
sshPort=<port>Full mode only; omitted in minimal and off modes.
cliPath=<path>Full mode only; omitted in minimal and off modes.

Security considerations:

  • Bonjour/mDNS TXT records carry no authentication. Clients must never treat TXT as authoritative for routing.
  • Clients should route based on the resolved service endpoint (SRV + A/AAAA). Regard lanHost, tailnetDns, gatewayPort, and gatewayTlsSha256 as mere hints.
  • SSH auto-targeting should likewise rely on the resolved service host rather than TXT-only hints.
  • TLS pinning must never permit an advertised gatewayTlsSha256 to supersede a previously stored pin.
  • iOS/Android nodes should treat discovery-based direct connects as TLS-only and demand explicit user confirmation before trusting a first-time fingerprint.

Debugging on macOS

Built-in utilities:

# Browse instances
dns-sd -B _openclaw-gw._tcp local.

# Resolve one instance (replace <instance>)
dns-sd -L "<instance>" _openclaw-gw._tcp local.

If browsing succeeds but resolution fails, a LAN policy or mDNS resolver issue is typically the cause.

Debugging in Gateway logs

The gateway maintains a rolling log file, announced at startup as gateway log file: .... Watch for bonjour: lines, particularly:

  • bonjour: advertise failed ...
  • bonjour: suppressing ciao netmask assertion ...
  • bonjour: ... name conflict resolved / hostname conflict resolved

OpenClaw launches each Bonjour service once and delegates probing, retry, name-conflict resolution, and interface-change republishing to the mDNS responder. This prevents overlapping publish attempts during routine network churn. Repeated internal self-probe messages are suppressed so they cannot overwhelm the gateway log.

When multiple OpenClaw gateways advertise from the same host, Bonjour may add suffixes such as (2) or (3) to keep service instance names distinct. These suffixes reflect normal conflict resolution and do not signal duplicate OCM supervision.

Bonjour employs the system hostname for the advertised .local host when it qualifies as a valid DNS label. If the system hostname includes spaces, underscores, or another invalid DNS-label character, OpenClaw falls back to openclaw.local. Set OPENCLAW_MDNS_HOSTNAME=<name> before starting the gateway when you need an explicit host label.

Debugging on iOS node

The iOS node relies on NWBrowser to locate _openclaw-gw._tcp.

For log capture: navigate to Settings -> Gateway -> Advanced -> Discovery Debug Logs, then Settings -> Gateway -> Advanced -> Discovery Logs -> reproduce the issue -> Copy. The captured log records browser state transitions and changes to the result set.

When to enable Bonjour

On macOS, Bonjour launches automatically when the gateway starts with an empty configuration, because the local app and nearby iOS or Android nodes typically depend on same-LAN discovery.

For Linux, Windows, or any other non-macOS host where same-LAN auto-discovery is beneficial, enable it explicitly:

openclaw plugins enable bonjour

When active, Bonjour relies on discovery.mdns.mode to determine the amount of TXT metadata to publish; the same setting also governs optional TXT hints in wide-area DNS-SD records. The modes are:

ModeBehavior
minimal (default)Only core TXT keys are included; sshPort, cliPath, and tailnetDns are left out.
fullAdds sshPort, cliPath, and tailnetDns; choose this when clients need those hints.
offDisables LAN multicast without altering plugin enablement; wide-area DNS-SD can still advertise when discovery.wideArea.domain is configured.

When to disable Bonjour

Keep Bonjour turned off when LAN multicast advertising serves no purpose, is unavailable, or poses a risk; typical scenarios include non-macOS servers, Docker bridge networking, WSL, or a network policy that blocks mDNS multicast. The gateway remains reachable via its published URL, SSH, Tailnet, or wide-area DNS-SD; only LAN auto-discovery becomes unreliable.

For deployment-scoped issues, use the environment override (suitable for Docker images, service files, launch scripts, and one-off debugging, since it vanishes with the environment):

OPENCLAW_DISABLE_BONJOUR=1

When you intentionally want to disable the bundled LAN discovery plugin for a particular OpenClaw configuration, use plugin configuration:

openclaw plugins disable bonjour

Docker gotchas

In detected containers, the bundled Bonjour plugin automatically disables LAN multicast advertising when OPENCLAW_DISABLE_BONJOUR is not set. Docker bridge networks typically fail to forward mDNS multicast (224.0.0.251:5353) between the container and the LAN, so advertising from the container rarely makes discovery function.

Gotchas:

  • Bonjour starts automatically on macOS hosts and is opt-in everywhere else. Leaving it disabled does not prevent the gateway from running; it merely skips LAN multicast advertising.
  • Disabling Bonjour leaves gateway.bind unchanged; Docker still defaults to OPENCLAW_GATEWAY_BIND=lan, so the published host port continues to work.
  • Wide-area DNS-SD remains active even with Bonjour disabled. Use wide-area discovery or Tailnet when the gateway and node are on different LANs.
  • Reusing the same OPENCLAW_CONFIG_DIR outside Docker does not carry over the container auto-disable policy.
  • Set OPENCLAW_DISABLE_BONJOUR=0 only for host networking, macvlan, or another network where mDNS multicast is confirmed to pass; use 1 to force-disable.

Troubleshooting disabled Bonjour

If a node stops auto-discovering the gateway after Docker setup:

  1. Verify whether the gateway runs in auto, forced-on, or forced-off mode:

    docker compose config | grep OPENCLAW_DISABLE_BONJOUR
    
  2. Confirm the gateway is reachable through the published port:

    curl -fsS http://127.0.0.1:18789/healthz
    
  3. When Bonjour is disabled, target it directly:

    • Control UI or local tools: http://127.0.0.1:18789
    • LAN clients: http://<gateway-host>:18789
    • Cross-network clients: Tailnet MagicDNS, Tailnet IP, SSH tunnel, or wide-area DNS-SD
  4. If you explicitly enabled the Bonjour plugin in Docker and forced advertising with OPENCLAW_DISABLE_BONJOUR=0, test multicast from the host:

    dns-sd -B _openclaw-gw._tcp local.
    

    If browsing returns empty results, or Gateway logs show repeated ciao probe failures, revert to OPENCLAW_DISABLE_BONJOUR=1 and use a direct or Tailnet route.

Common failure modes

  • Bonjour does not span networks: rely on Tailnet or SSH.
  • Multicast blocked: certain Wi-Fi networks suppress mDNS.
  • Advertiser stuck in probing/announcing: blocked multicast, container bridges, WSL, or interface churn can leave the responder in a non-announced state. The gateway stays accessible through direct, SSH, Tailnet, or wide-area DNS-SD routes; disable LAN Bonjour with discovery.mdns.mode: "off" or OPENCLAW_DISABLE_BONJOUR=1 when multicast is unavailable.
  • Docker bridge networking: Bonjour auto-disables in detected containers. Set OPENCLAW_DISABLE_BONJOUR=0 only for host, macvlan, or another mDNS-capable network.
  • Sleep/interface churn: macOS may temporarily drop mDNS results; retry.
  • Browse works but resolve fails: keep machine names simple (avoid emojis or punctuation), then restart the gateway. The service instance name derives from the host name, so overly complex names can confuse some resolvers.

Escaped instance names (\032)

Bonjour/DNS-SD often escapes bytes in service instance names as decimal \DDD sequences (spaces become \032). This is normal at the protocol level; UIs should decode for display (iOS uses BonjourEscapes.decode).

Enabling / disabling / configuration

SettingEffect
openclaw plugins enable bonjourTurns on the built-in LAN discovery plugin for hosts where it isn't already active by default.
openclaw plugins disable bonjourStops LAN multicast advertising by turning off the bundled plugin.
OPENCLAW_DISABLE_BONJOUR=1 (or true/yes/on)Halts LAN multicast advertising while leaving plugin configuration untouched.
OPENCLAW_DISABLE_BONJOUR=0 (or false/no/off)Compels LAN multicast advertising to run, even within recognized containers.
discovery.mdns.modeoff | minimal (default) | full, refer to the modes described earlier.
gateway.bindDictates the gateway bind mode as defined in ~/.openclaw/openclaw.json.
OPENCLAW_SSH_PORTChanges the SSH port used when sshPort gets advertised (full mode).
OPENCLAW_TAILNET_DNSEmits a MagicDNS hint in TXT whenever mDNS full mode is active.
OPENCLAW_CLI_PATHAlters the advertised CLI path (full mode).

By default, macOS hosts launch the bundled LAN discovery plugin automatically. With the Bonjour plugin active and OPENCLAW_DISABLE_BONJOUR left unset, advertising happens on standard hosts and switches off automatically inside recognized containers (Docker, Fly.io machines, and typical container runtimes).

1,883 words · updated Aug 24, 2026