Skip to content

Runbook: Tailscale

How the tailnet is wired and the non-obvious behaviors that bite. Tailscale is not managed from this repo (no config file here) — it's daemon state on av plus the admin console. This is the written record. Companion: docs/runbooks/dns.md (the DNS model leans directly on the routes below).

Tailnet: anaconda-perch.ts.net · av = machine ascertain-verse, 100.98.53.7 / fd7a:115c:a1e0::4001:3507 · operator: skill-lava (so tailscale set/up on av need no sudo) · MagicDNS suffix: anaconda-perch.ts.net.

1. Two kinds of address — the distinction everything hinges on

Every tailnet node has a native address (100.x + a fd7a:… ULA) reachable by every peer over the WireGuard mesh, no opt-in required. Separately, a node can act as a subnet router and advertise routes to other IPs/CIDRs; those are reachable only by peers that have accepted routes (--accept-routes, off by default on Linux; on by default on mobile). This split is the root of both the DNS design (§3) and the sharing gotcha (§4).

2. av as a subnet router

av advertises its own LAN addresses as /32 and /128 routes so off-LAN tailnet devices can reach LAN services. Current state (tailscale status --jsonSelf.PrimaryRoutes = the approved set):

Route Purpose Status
192.168.86.49/32 av's LAN IPv4 (the A record) reachable off-LAN ✅ approved
fd00:6176::49/128 av's LAN IPv6 ULA (the fd00:6176 AAAA) reachable off-LAN ⚠️ advertise + approve pending (2026-08-02)
0.0.0.0/0, ::/0 av offered as an exit node ✅ approved (available to peers)
  • IPv6 forwarding is on (net.ipv6.conf.all.forwarding=1, ip_forward=1) — required for the subnet router; already set, no sysctl change needed for the /128.
  • Advertising ≠ active. A newly advertised route stays unusable until approved in the admin console (Machines → ascertain-verse → ⋯ → Edit route settings; exit nodes are approved the same way). No auto-approver — approval is manual. Check subnet routes with tailscale status --json | jq '.Self.PrimaryRoutes'; exit-node approval shows as Self.ExitNodeOption: true.
  • Set what av advertises (operator, no sudo): tailscale set --advertise-routes=192.168.86.49/32,fd00:6176::49/128 --advertise-exit-node — the two subnet routes plus the exit-node offer. (av previously also advertised 192.168.86.33/32; removed 2026-07-29 as unneeded.)

3. How DNS depends on this (see dns.md)

Public DNS publishes, for every *.fmm.house name, A .49 + two AAAAs: fd00:6176 (LAN ULA) and fd7a (native). Each audience uses the address it can route to (Happy Eyeballs races them):

  • LAN device.49/fd00:6176 directly (same link).
  • On-tailnet, off-LAN, accepts routes.49/fd00:6176 via the approved /32 + /128.
  • On-tailnet, off-LAN, doesn't accept routesfd7a (native; the routes are invisible to it).
  • Shared-in user (see §4) → fd7a only.

fd7a is published specifically so the last two cases work — dropping it (a brief 2026-07-19 experiment) broke node sharing.

4. Node sharing — the gotcha ⚠️

You share individual machines out to other people's tailnets (the device-of-shared-to-user peers). Sharing a machine exposes only that machine's own native Tailscale address — never its subnet routes. Straight from Tailscale's docs: "Shared machines do not advertise subnets to the tailnets they're shared into."

Consequence for us: a person you've shared av with can reach av's 100.98.53.7 / fd7a:…, but not 192.168.86.49/32 or fd00:6176::49/128. So when they resolve bz.fmm.house (public DNS → .49 + fd00:6176 + fd7a), the only address they can actually route to is fd7a. That is why the public zone must keep fd7a published even though LAN/tailnet clients prefer fd00:6176.

  • AdGuard is irrelevant to shared users — they're on their own tailnet and resolve fmm.house via public DNS, never av's AdGuard. (AdGuard serves fd00:6176 only; see dns.md §2b.)
  • If a shared user ever needs full subnet access (not just av), the alternative is to invite them into this tailnet instead of sharing a node — invited users do get subnet routers. Bigger blast radius; not currently done.

5. Exit nodes

av is an approved exit node (ExitNodeOption: true, §2) — tailnet peers may route all their traffic out through it. av itself is not using an exit node (ExitNodeID empty). Other peers also offering exit-node service: homeassistant, teka, kvm-teka, bedroom-a-box. Nothing in the homelab depends on exit nodes; listed for inventory.

6. Operations

tailscale status                       # peers, who's online, who advertises what
tailscale status --json | jq '.Self.PrimaryRoutes'   # approved routes on av
tailscale debug prefs | jq '{OperatorUser,RouteAll,AdvertiseRoutes,ExitNodeID}'
tailscale set --advertise-routes=<csv> # (re)advertise subnet routes — then APPROVE in the console
tailscale set --accept-routes=true     # this node uses others' subnet routes
  • Approval and sharing are console-only — the CLI can advertise/accept, but approving a route or sharing a node is done at https://login.tailscale.com/admin/machines. Route acceptance is a per-device local pref and is not visible from av (not in status/netmap/API) — the only way to know is to check the device or test.
  • Reboots: av's Tailscale comes back on its own; the LUKS/boot fragility is a Docker concern, not a Tailscale one (see dns.md §5d).

7. Cross-references

  • docs/runbooks/dns.md — the resolution model that rides on §2's routes (§1 table, §7).
  • docs/architecture.md — network model summary.
  • Memory: dns-spec-and-reboot-fragility.