mcpField
T
tailscale-docker-debug

tailscale-docker-debug

github.com/rshadeCloud & DevOps393 installsUpdated 2w ago
Repository

About tailscale-docker-debug

Tailscale Docker Debug is a troubleshooting skill for connectivity and DNS problems in Tailscale containers. Its six-step workflow checks runtime mode, TUN, resolver routing, tailnet conflicts, and MagicDNS.

Key features

  1. 01Check kernel or userspace runtime mode
  2. 02Verify TUN interface and Tailscale IP
  3. 03Inspect DNS resolver configuration and routes
  4. 04Detect host and container tailnet conflicts
  5. 05Validate MagicDNS resolution end to end

Use cases

  1. 01Diagnose DNS failures in Docker containers
  2. 02Debug a host and container on different tailnets
  3. 03Investigate TUN issues after moving to Compose

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/rshade/agent-skills --skill tailscale-docker-debug

After installing, type/tailscale-docker-debugin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

evals/
evals.json
references/
common-failures.md
compose-configuration-matrix.md
dns-resolver-chain.md

Details

From the project README

Tailscale Docker Debug

Diagnose and fix Tailscale connectivity and DNS issues inside Docker containers. Runs six sequential checks covering the full debugging chain from container runtime mode through MagicDNS resolution.

What this skill does

  1. Detects whether the container runs in kernel or userspace mode.
  2. Verifies the TUN interface exists with a Tailscale IP.
  3. Checks the DNS resolver chain for misrouted queries.
  4. Confirms 100.100.100.100 routes through the container's Tailscale.
  5. Detects multi-tailnet conflicts between host and container.
  6. Validates MagicDNS end-to-end with a name resolution test.

Common triggers

  • Customer reports "DNS doesn't work" inside Docker/Podman containers
  • Host on one tailnet, containers on a different tailnet
  • Compose file has NET_ADMIN and /dev/net/tun but Tailscale still runs in userspace mode
  • Migration from docker run to docker compose breaks TUN

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 — Detect container runtime mode
docker logs <container> 2>&1 | grep -iE "tun|userspace|netstack"

Pass: Logs show tun "tailscale0" — kernel mode. Proceed to step 2.

Fail: Logs show --tun=userspace-networking. The official tailscale/tailscale image defaults to userspace via containerboot regardless of capabilities.

Fix: Set TS_USERSPACE=false in environment. Use devices: (not volumes:) for /dev/net/tun. Add cap_add: [NET_ADMIN, SYS_MODULE]. See references/compose-configuration-matrix.md for the full config.

Step 2 — Verify TUN interface exists
docker exec <container> ip addr show tailscale0

Pass: Interface shows a 100.x.y.z/32 address. Proceed to step 3.

Fail: No tailscale0 interface even with TS_USERSPACE=false.

Fix: Change /dev/net/tun from volumes: to devices: in compose. Verify the device exists in the container with major/minor 10, 200. Confirm cap_add: [NET_ADMIN, SYS_MODULE].

Step 3 — Check DNS resolver chain
docker exec <container> cat /etc/resolv.conf

Examine three things:

  • nameserver — expect 127.0.0.11 (Docker embedded DNS)
  • External servers — should forward to 100.100.100.100
  • search — should match the container's tailnet, not the host's

Fail indicators:

  • ExtServers: [host(127.0.0.53)] — Docker forwards to host systemd-resolved instead of Tailscale
  • Search domain belongs to a different tailnet

Fix: Add dns: [100.100.100.100] to each service in compose. See references/dns-resolver-chain.md for the full resolution path.

Step 4 — Verify 100.100.100.100 routing
docker exec <container> ip route get 100.100.100.100

Pass: Routes via tailscale0 or a local interface.

Fail: Routes via eth0 or Docker gateway (e.g., via 172.18.0.1) — DNS queries escape to the host.

docker exec <container> ss -ulnp | grep 100.100

Fix: This is a symptom of step 1 (userspace mode) or step 2 (missing TUN). Fix those first.

Step 5 — Detect multi-tailnet conflict
docker exec <container> tailscale status | head -1
docker exec <container> grep search /etc/resolv.conf

Compare the tailnet shown in tailscale status against the search domain in resolv.conf.

Fail: Search domain (inherited from host) doesn't match the container's tailnet. Example: host on tucuxi-lungfish.ts.net, container on tail9a660c.ts.net.

Fix: Add dns_search: [<correct-tailnet>.ts.net] in compose, or use FQDNs exclusively. Root cause is Docker inheriting the host's resolv.conf search domain.

Step 6 — Verify MagicDNS end-to-end
docker exec <container> tailscale dns status | head -3

Pass: Shows Tailscale DNS: enabled.

Fail: Shows Tailscale DNS: disabled.

Fix: Set TS_ACCEPT_DNS=true in environment.

Final validation:

docker exec <container> nslookup <peer>.<tailnet>.ts.net 100.100.100.100
docker exec <container> ping -c 1 <peer>.<tailnet>.ts.net

If both succeed, MagicDNS is working correctly inside the container.

Error handling

Do not silently skip a failed check. Report the specific failure with the fix before continuing. If a fix requires restarting the container, instruct the user to recreate it (docker compose up -d) and rerun the workflow from step 1.

The log message getting OS base config is not supported is non-fatal — Tailscale cannot read the container's DNS config directly. Fix DNS via the compose file instead.

References

  • references/compose-configuration-matrix.md — minimum compose config for kernel-mode Tailscale with MagicDNS, setting-by-setting breakdown
  • references/dns-resolver-chain.md — full DNS resolution path through Docker embedded DNS, short name vs FQDN conflict
  • references/common-failures.md — symptom-based lookup table with root causes and fixes

Comments

Markdown supported