tailscale-serve-patternslisted
Install: claude install-skill technicalpickles/pickled-claude-plugins
# Tailscale Serve Patterns
## Overview
Two ways to make a local service reachable over a tailnet, with very different security properties: bind loopback-only and let `tailscale serve` proxy HTTPS in front of it, or bind the process directly to the tailnet interface address. For CLI mechanics (commands, Services vs. node-serve, troubleshooting `serve status`), see the `tailscale-cli` skill instead — this skill is about which exposure shape to choose and what it implies for auth.
## The two binding patterns
| | Loopback bind + `tailscale serve` | Direct bind to tailnet interface |
|---|---|---|
| What's exposed | `127.0.0.1:<port>` only; `serve` proxies HTTPS at `<host>.<tailnet>.ts.net` | Plain HTTP directly at the tailnet IP (e.g. `100.x.y.z:<port>`) |
| Auth | Tailscale itself is the gate — only tailnet members can reach the hostname at all; TLS terminated by `tailscaled` | None unless the app adds its own — anyone on the tailnet who knows the IP:port can hit it over unencrypted HTTP |
| Setup cost | One extra `tailscale serve` mapping to create/tear down | Zero extra config — just bind a different address |
| Failure mode if misconfigured | Hitting `<tailnet-hostname>:<port>` directly (skipping the proxy) fails, because the app only bound loopback — this is *expected*, not a bug | A stray bind flag or default (`0.0.0.0` instead of `127.0.0.1`) silently widens exposure to the whole tailnet with no signal |
**Default to loopback + `serve`.** It's the pattern used across