Files
magnus919_agent-skills/bundles/tailscale/references/routing-reference.md
T
Magnus Hedemark 96caf3ae06 feat: add tailscale bundle — self-hosted Tailscale/Headscale skill collection
Adds the first bundle to the agent-skills repo under bundles/:
a collection of 7 sub-skills for managing the self-hosted
Tailscale/Headscale VPN ecosystem.

Includes 23 scripts (bash + python), 8 reference documents,
6 deployment templates, and a context-aware umbrella SKILL.md
that auto-loads sub-skills by trigger keywords.
2026-05-28 00:14:30 -04:00

3.2 KiB

Routing Reference — Subnet Routers & Exit Nodes

Subnet Routers

A subnet router extends the tailnet to devices that can't run the Tailscale client (printers, NAS devices, IoT, etc.).

Setup

  1. On the gateway node (the machine that can reach the target subnet):
tailscale up --login-server https://headscale.example.com --advertise-routes=192.168.1.0/24 --accept-routes
  1. Approve the route in Headscale:
headscale routes list                     # Find route ID
headscale routes enable <route-id>        # Approve
  1. On client nodes that need access:
tailscale up --login-server https://headscale.example.com --accept-routes

Auto-Approval

Configure headscale policy to auto-approve routes:

{
  "autoApprovers": {
    "routes": {
      "192.168.0.0/16": ["alice@"],
      "10.0.0.0/8": ["autogroup:admin"]
    }
  }
}

Route Filtering (Grants Via)

Restrict cross-subnet access to specific ports:

{
  "grants": [
    {
      "src": ["autogroup:member"],
      "dst": ["tag:gateway"],
      "ip": ["*"],
      "via": ["192.168.1.0/24:80,443"]
    }
  ]
}

SNAT (Source NAT)

By default, subnet router traffic appears to originate from the router's own IP. Disable --snat-subnet-routes=false if the subnet needs to see the origina-tailing client's tailnet IP (requires proper routing back).

Exit Nodes

An exit node routes all internet traffic from other tailnet clients through the exit node's internet connection.

Setup

  1. On the exit node (the machine that will provide internet access):
tailscale up --advertise-exit-node
  1. Approve in Headscale:
headscale routes list                     # Find the exit node route
headscale routes enable <route-id>
  1. On client devices:
# Use a specific exit node
tailscale up --exit-node=100.x.y.z

# Or, to use an exit node while still accessing local LAN
tailscale up --exit-node=100.x.y.z --exit-node-allow-lan-access

Auto-Approval for Exit Nodes

{
  "autoApprovers": {
    "exitNode": ["tag:gateway", "alice@"]
  }
}

Route Management Commands

Headscale server side:

headscale routes list                               # All routes
headscale routes list --node <node-id>              # Routes for one node
headscale routes enable <route-id>                  # Approve/Enable
headscale routes disable <route-id>                 # Disable
headscale routes delete <route-id>                  # Remove route

Client side:

tailscale up --advertise-routes=10.0.0.0/24          # Advertise subnet
tailscale up --advertise-routes=10.0.0.0/24,192.168.1.0/24  # Multiple subnets
tailscale up --advertise-exit-node                   # Advertise as exit node
tailscale up --accept-routes                         # Accept all advertised routes
tailscale up --exit-node=100.x.y.z                   # Use an exit node
tailscale up --exit-node-allow-lan-access            # Allow LAN with exit node

Diagnostics

# Check if routes are accepted
tailscale status --json | jq '.Peer[].Routes'

# Check which exit node is active
tailscale status | grep -E '^100\.'

# Check subnet router status
tailscale status --self --json | jq '.Self.Routes'