# Tailscale Funnel 端口冲突调试笔记

## 场景
- Tailscale 运行在 userspace-networking 模式（`--tun=userspace-networking`）
- Funnel 已配置：`tailscale serve http://localhost:5678` + `tailscale funnel on`
- Funnel URL: `https://kuhnn-lenovo-ideapad-710s-13isk.tail95fef0.ts.net/`
- N8n 通过 Docker 暴露 5678 端口

## 问题现象
- Funnel 状态显示 `AllowFunnel: true` 和 `"TCP": {"443": {"HTTPS": true}}`
- 但外部访问返回 Synology Web Station 页面（不是 n8n）
- 公网 IP:443 被 Docker Caddy 截获

## 诊断命令

### 1. Funnel 状态（JSON 解析）
```bash
tailscale --socket=/tmp/tailscaled.sock funnel status --json 2>/dev/null | python3 -c "
import sys, json
d = json.load(sys.stdin)
print('AllowFunnel:', d.get('AllowFunnel', {}))
print('TCP:', d.get('TCP', {}))
print('BackendState:', d.get('BackendState', ''))
"
```

关键字段：
- `AllowFunnel`: `{ "<funnel-url>:443": true }` = 配置已接受
- `TCP.443.HTTPS`: `true` = Funnel 声称在 443 监听
- **注意**：userspace 模式下这些是配置声明，不是实际端口监听证明

### 2. 谁在占用 443
```bash
ss -tlnp | grep :443
# 输出：docker-proxy 进程占用 0.0.0.0:443 → Caddy 容器
```

### 3. tailscaled 的 TCP 连接
```bash
ss -tp | grep tailscaled
# userspace 模式：tailscaled 有连接到 DERP 服务器的 ESTAB 连接
# 但没有监听本地端口的记录（不同于 TUN 模式）
```

### 4. Funnel 日志
```bash
tailscale --socket=/tmp/tailscaled.sock funnel status 2>&1
# 显示 "tailnet only" = 仅 Tailscale 内网可访问
# vs "Available on the internet" = 公网可访问
```

## 根因
Docker Caddy 容器以 `EXPOSE -p 443:443` 映射到主机 0.0.0.0:443。Tailscale Funnel 在 userspace 模式下无法真正抢占端口，流量被 Docker 层的 iptables/nftables 规则截获。

## 解决步骤
1. `sudo docker stop caddy` — 停止 Caddy 释放 443
2. `sudo systemctl restart systemd-resolved` — 重启 DNS 解析
3. 验证：`ss -tlnp | grep :443` 应只剩 tailscaled 相关条目
4. 测试外部访问 Funnel URL

## 关键教训
- Funnel 的 `AllowFunnel: true` **不等于** 公网可访问
- userspace 模式下 Funnel "声称"占用 443，但 Docker 端口映射在网络层有更高优先级
- 必须用外部测试（`curl https://<funnel-url>` 从另一网络）验证，不能只看 Funnel 状态 JSON
