# Adding a Path to Existing Tailscale Funnel

When Tailscale Funnel is already running with multiple handlers on port 443,
adding a new path prefix requires full config reset + rebuild.

## Problem

```bash
tailscale serve --set-path /new-site/ http://127.0.0.1:8999
# → "listener already exists for port 443"
```

The same error occurs with `tailscale funnel --set-path ...` if funnel is already active.

## Procedure

### 1. Snapshot current config

```bash
tailscale serve status -json > /tmp/ts-serve-backup.json
```

### 2. Reset everything

```bash
tailscale serve reset
tailscale funnel reset   # if funnel was active
```

### 3. Rebuild ALL handlers on each port

For each port that had handlers, re-add them one at a time. Example for port 443:

```bash
# Add all paths for HTTPS port 443 (the --bg keeps it running)
tailscale serve --bg --set-path /          http://127.0.0.1:5000
tailscale serve --bg --set-path /api/      http://127.0.0.1:8420
tailscale serve --bg --set-path /new-site/ http://127.0.0.1:8999
```

For port 80 (HTTP only, no TLS):

```bash
tailscale serve --bg --http=80 --set-path /health http://127.0.0.1:3007
```

For port 8443 (alternate HTTPS):

```bash
tailscale serve --bg --https=8443 --set-path /         http://127.0.0.1:3017
tailscale serve --bg --https=8443 --set-path /hevy-api/ http://127.0.0.1:8420
```

### 4. Re-enable Funnel for each port that needs public access

```bash
tailscale funnel --bg --set-path /          http://127.0.0.1:5000
tailscale funnel --bg --set-path /api/      http://127.0.0.1:8420
tailscale funnel --bg --set-path /new-site/ http://127.0.0.1:8999
tailscale funnel --bg --https=8443 --set-path / http://127.0.0.1:3017
```

### 5. Verify

```bash
tailscale serve status
curl -s -o /dev/null -w "%{http_code}" https://HOST.tailnet.ts.net/new-site/
```

## Key Lessons

- **Funnel paths must match serve paths exactly.** Every path served must also be funneled if you want public access.
- **`--bg` flag is needed for each handler** when rebuilding to keep the daemon running.
- **The old `tailscale funnel 443 on` syntax is deprecated.** Use `--set-path` like serve.
- **Paths are matched most-specific-first.** Adding `/led/` while `/` exists as catch-all works — the specific path takes priority.
- **Tailscale Funnel provides automatic Let's Encrypt TLS.** No cert management needed — critical for Web Bluetooth API which requires HTTPS.
