Files
magnus919_agent-skills/tailscale/references/routing-reference.md
T
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> c0c7690724 feat(flatten): move bundle dirs to repo root
Move the 8 directories under bundles/ to the repo root via git mv and
remove the now-empty bundles/ directory. Replace the "bundles" entry in
pyproject.toml [tool.deptry] extend_exclude with the 8 moved dir names so
the moved trees stay excluded from Python dependency analysis.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-14 15:26:27 -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'