tailscale-subnet-router-debug
>
Works with
---
name: tailscale-subnet-router-debug
description: >
license: Apache-2.0
---
# Tailscale Subnet Router Debug
Diagnose and fix Tailscale subnet router connectivity failures. Runs
seven sequential checks covering the full route lifecycle from
advertisement through return path verification.
## What this skill does
1. Verifies the subnet router advertises the route.
2. Confirms the route is approved (admin console or autoApprovers).
3. Checks that clients accept subnet routes (`--accept-routes`).
4. Inspects policy routing table 52 for installed routes.
5. Validates IP forwarding is enabled on the subnet router.
6. Tests that the subnet router can reach the target directly.
7. Verifies the return path for response traffic.
## Common triggers
- Client can ping the subnet router but not devices on the advertised subnet
- Route shows approved in admin console but `ip route` is empty
- Docker containers fail to advertise routes via `TS_ROUTES`
- Traffic flows to the target but responses never come back
- "It works from the router itself but not from other clients"
## Diagnostic workflow
Run each step in order. Stop at the first failure and apply the fix
before continuing — later steps depend on earlier ones.
### Step 1 — Verify route is advertised
```bash
tailscale status --json | jq '.Self.AllowedIPs'
```
**Pass:** Subnet CIDR appears in AllowedIPs (e.g., `10.100.0.0/24`).
**Fail:** Only Tailscale IPs shown. Route not advertised.
**Fix:** `tailscale set --advertise-routes=<CIDR>`. In Docker, check
`TS_ROUTES` env var — it may not take effect if auth failed on first
boot. Fall back to `tailscale set` at runtime.
### Step 2 — Verify route is approved
Check admin console, or from a **peer node**:
```bash
tailscale status --json | jq '.Peer[] | select(.HostName=="<router>") | .AllowedIPs'
```
**Pass:** Subnet CIDR appears in the peer's view of the router's AllowedIPs.
**Fail:** Only Tailscale IPs shown from peer perspective. Route is
pending approval.
**Fix:** Approve in admin console, or add `autoApprovers` to ACL:
```json
"autoApprovers": {
"routes": { "10.100.0.0/24": ["tag:subnet"] }
}
```
### Step 3 — Verify client accepts routes
```bash
tailscale debug prefs | grep -i route
```
**Fail:** `--accept-routes` is false (the default). Clients ignore
advertised subnet routes even when approved.
**Fix:** `tailscale set --accept-routes=true`. In Docker, add
`--accept-routes` to `TS_EXTRA_ARGS`. Do not use `tailscale down` in
Docker — it kills containerboot. Use `tailscale set` instead.
### Step 4 — Verify route in policy routing table
```bash
ip route show table 52
```
**Pass:** Shows route for subnet CIDR via `dev tailscale0`.
**Fail:** Table 52 is empty or missing the subnet route.
**Critical:** `ip route` (no table) only shows the main table. Tailscale
uses policy routing table 52 — routes will NOT appear in default output.
This is the most common false negative.
Also check:
```bash
ip rule show
```
See `references/policy-routing.md` for details on table 52 and how
Tailscale's policy routing works.
### Step 5 — Verify IP forwarding on the subnet router
```bash
cat /proc/sys/net/ipv4/ip_forward
```
**Pass:** Returns `1`.
**Fail:** Returns `0`. Kernel drops forwarded packets silently.
**Fix:** `sysctl -w net.ipv4.ip_forward=1`. In Docker Compose, set
`sysctls: [net.ipv4.ip_forward=1]`. For persistence on Linux hosts,
add to `/etc/sysctl.d/`.
### Step 6 — Verify network path from subnet router to target
From the subnet router:
```bash
ping <target-ip>
ip addr show
```
**Pass:** Router can reach the target and has an interface on the
advertised subnet.
**Fail:** Router cannot reach the target. This is a local network issue
(firewall, VLAN, routing) — not Tailscale.
### Step 7 — Verify return path
The target must route responses back through the subnet router. If the
target's default gateway is not the subnet router, return traffic takes
a different path and gets dropped.
**Fix:** Add a static route on the target (or its gateway) for
`100.64.0.0/10` pointing to the subnet router's internal IP. Or enable
masquerading:
```bash
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
```
Tailscale 1.64+ enables `--snat-subnet-routes` by default, which
handles this automatically.
## Error handling
Do not silently skip a failed check. Report the specific failure with
the fix before continuing. If a fix requires restarting Tailscale or
recreating a container, instruct the user to do so and rerun from
step 1.
## References
- `references/route-lifecycle.md` — full 7-stage route lifecycle from
advertisement through return path
- `references/policy-routing.md` — table 52, ip rule, VRF analogy,
and why `ip route` misses Tailscale routes
- `references/common-failures.md` — symptom-based lookup table with
root causes and fixesMore Debugging skills
diagnosing-bugs
mattpocock/skills
Diagnosis loop for hard bugs and performance regressions. Use when the user says "diagnose"/"debug this", or reports something broken/throwing/failing/slow.
explore-code
lllllllama/rigorpilot-skills
Rigor Improve implementation leaf skill for auditable candidate implementation in deep learning research repositories. Use when the researcher explicitly authorizes exploratory work on an isolated branch or worktree to transplant modules, adapt a backbone, add LoRA or adapter layers, replace a head, or stitch together meaningful low-risk migration ideas with rollback-aware records in `explore_outputs/`. Do not use for end-to-end exploration orchestration on top of `current_research`, trusted baseline reproduction, conservative debugging, environment setup, verified contribution claims, or default repository analysis.
safe-debug
lllllllama/rigorpilot-skills
Rigor Debug / Rigor Audit skill for deep learning research work. Use when the user pastes a traceback, terminal error, CUDA OOM, checkpoint load failure, shape mismatch, NaN loss symptom, or training failure and wants conservative diagnosis before any patching, with debug fixes clearly separated from research contributions. Do not use for broad refactoring, speculative adaptation, automatic exploratory patching, or general repository familiarization.

