Cluster.Strategy.TailscaleLocal (libcluster_mesh v0.1.0)

Copy Markdown View Source

libcluster strategy that discovers peers by polling the local Tailscale daemon via tailscale status --json.

Unlike strategies built on the Tailscale cloud API, this works with any control server speaking the Tailscale protocol — including self-hosted Headscale and Headscale-based products — because peer information comes from the node's own daemon, and requires no API key.

The name follows tailscaled's own "LocalAPI" and deliberately avoids clashing with Cluster.Strategy.Tailscale from libcluster_tailscale, which discovers peers through the Tailscale cloud API instead; the two can coexist in one project. This strategy requires tailscaled to be running on the node itself — for nodes that reach the tailnet only indirectly (e.g. via a subnet router), use the cloud API strategy. See the README for a full comparison.

Usage

Start every node with a longname built from its mesh IPv4 and a shared basename (e.g. myapp@100.64.0.7), then configure:

config :libcluster,
  topologies: [
    tailnet: [
      strategy: Cluster.Strategy.TailscaleLocal,
      config: [
        node_basename: "myapp",
        hostnames: ["myapp-"],
        # cli: "/Applications/Tailscale.app/Contents/MacOS/Tailscale",
        # polling_interval: 5_000
      ]
    ]
  ]

Options

  • node_basename (required) — node name part before @, shared by all nodes
  • hostnames (required) — list of mesh hostname prefixes that identify cluster members; peers not matching any prefix are ignored
  • cli — path to the tailscale binary (default "tailscale")
  • polling_interval — poll interval in milliseconds (default 5_000)
  • cmd_timeout — CLI timeout in milliseconds (default 10_000; polls never overlap regardless, as the next poll is scheduled after the current one)
  • runnerLibclusterMesh.Runner implementation (default runs the CLI)