# Tailscale 固定地址接入（2026-10-13）

## 目标

解决 Cloudflare 快速隧道「地址会变、隧道被注销」的根本问题。

## 最终方案：Tailscale Funnel

**固定公网地址（永久不变、任何设备任何网络可访问、无需安装客户端）：**

```
https://desktop-ue6cc4h.tail87341f.ts.net/reports/dashboard/index.html
```

```
公网 → Tailscale Funnel → tailscaled → http://127.0.0.1:8765
```

```powershell
$ts='C:\Program Files\Tailscale\tailscale.exe'
& $ts funnel --bg 8765    # 开启公网发布
& $ts funnel status       # 应显示 "Funnel on"
& $ts serve --bg 8765     # 仅 tailnet 内访问（可选，与 Funnel 共存）
```

Funnel 的三大好处：**不需要开端口、不需要防火墙规则、不需要域名**——
因为流量走 tailscaled 已建立的出站隧道。

> 用户在 2026-10-14 明确选择：**保持公开、不加密码**。
> 因此看板目前无认证，任何拿到链接的人都可访问。

### Cloudflare 隧道已退役（2026-10-14）

原 `deploy\start_tunnel.ps1` 已重命名为 **`start_tunnel.ps1.retired`**，
`tools\cloudflared.exe` 保留但不再运行，看门狗中的隧道管理逻辑已移除。

**退役时发现的关键问题**：一个 **9-14 启动的 `start_tunnel.ps1` 已持续运行 29.7 天**，
内含 `while($true)` 重启循环，每次杀掉 cloudflared 它都会把隧道拉回来。
这解释了为什么"改动看起来没生效"——**旧启动器循环在背后覆盖配置**。
（同类问题此前也出现在 `start_dashboard_server.ps1` 上。）

## 完成情况

### ✅ 全部完成

| 步骤 | 结果 |
| --- | --- |
| Tailscale 登录 | ✅ 账号 `jyfssdls@outlook.com` |
| 设备入网 | ✅ `desktop-ue6cc4h` |
| 后台状态 | ✅ `BackendState: Running` |
| **固定 IP** | ✅ **`100.120.247.24`**（永久不变） |
| **固定 HTTPS 地址** | ✅ **`https://desktop-ue6cc4h.tail87341f.ts.net`** |
| 看板监听 | ✅ `0.0.0.0:8765` |
| Serve 证书 | ✅ 已签发（`tailscale cert` 成功） |

### 三种访问方式（本机全部实测 HTTP 200）

```
https://desktop-ue6cc4h.tail87341f.ts.net      ← 推荐，固定 + HTTPS
http://100.120.247.24:8765                      ← 固定 IP
http://127.0.0.1:8765                           ← 本机
```

## ⚠️ 还需要验证：防火墙

防火墙三个配置文件**全部开启**，且检查发现：

- **没有任何**含 `tailscale` 的规则
- **没有**针对 `100.64.0.0/10` 的规则
- **没有**放行 8765 或 443 的规则
- **没有** python 相关规则

**同机测试能通是因为本机流量绕过防火墙**，其他设备（手机/笔记本）可能被入站拦截。

### 先在手机上试一下

用手机装 Tailscale 登录同一账号，打开：

```
https://desktop-ue6cc4h.tail87341f.ts.net/reports/dashboard/index.html
```

**能打开 → 不用做任何事。**
打不开 → 用**管理员 PowerShell** 执行：

```powershell
New-NetFirewallRule -DisplayName "Tailscale tailnet access" `
  -Direction Inbound -Action Allow -Protocol TCP -LocalPort 443,8765 `
  -RemoteAddress 100.64.0.0/10 -Profile Any
```

> `-RemoteAddress 100.64.0.0/10` 把放行**限制在 Tailscale 网段**，
> 不会暴露给局域网，也不会暴露到公网。同时放行 443（Serve 的 HTTPS）和 8765（直连）。

## 手机/笔记本怎么用

1. 安装 **Tailscale**，登录**同一账号**（`jyfssdls@outlook.com`）
2. 打开 `https://desktop-ue6cc4h.tail87341f.ts.net/reports/dashboard/index.html`
3. 建议加书签——**这个地址永久不变**

## 改动记录

### `serve_dashboard.py`

绑定地址改为可选参数，默认仍是 `127.0.0.1`（不主动暴露）：

```python
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8765
host = sys.argv[2] if len(sys.argv) > 2 else "127.0.0.1"
server = ThreadingHTTPServer((host, port), handler)
```

### `deploy/start_dashboard_server.ps1`

新增 `$BindHost = '0.0.0.0'` 并传给 python。

> 注：走 `tailscale serve` 时其实只需要监听 `127.0.0.1`
> （Serve 代理的是 127.0.0.1:8765）。保留 `0.0.0.0` 是为了同时支持
> 直连 Tailscale IP 访问，两种方式都能用。

## 排查中踩的坑

1. **`tailscale up` 必须列全非默认参数**，否则报
   `requires mentioning all non-default flags`。正确写法：
   `tailscale up --force-reauth --accept-routes=false`
2. **后台卡在 `NoState`**（云端已登录但本机不生效）：
   光跑 CLI 没用，**启动 GUI（`tailscale-ipn.exe`）后才转为 `Running`**。
3. **`tailscale serve` 需要先在后台开启 Serve**（本次已开启，证书签发成功）。
4. **旧启动器进程会覆盖改动**：`start_dashboard_server.ps1` 内含 `while($true)` 重启循环，
   9-14 启动的那个旧实例一直活着，杀掉 python 后是**它**用旧参数把 python 拉起来的，
   新代码没生效。必须先杀掉旧启动器进程。
5. **过滤进程时匹配到了自己**：命令里含 `start_dashboard_server` 字样，
   导致过滤器匹配到自身，把我自己的 PowerShell 也杀了，后续命令没执行。
   → 过滤要写成 `-like '*-File*start_dashboard_server.ps1*'` 并排除 `$PID`。
6. **`tailscale cert` 会把证书和私钥写到当前工作目录**。
   已删除遗留的 `*.crt` / `*.key`（Serve 自己管理证书，不需要这些文件）。

## 与 Cloudflare 隧道的对比

| | Cloudflare 快速隧道 | **Tailscale** |
| --- | --- | --- |
| 费用 | 免费 | 免费 |
| 地址稳定性 | ❌ 重启即变，且会被服务端注销（实测 5～24 天） | ✅ **永久不变** |
| 协议 | HTTPS | ✅ HTTPS（经 Serve） |
| 谁能访问 | 任何拿到链接的人 | 仅登录同一账号的设备 |
| 需要域名 | 命名隧道需要 | 不需要 |

**建议**：日常用 Tailscale 固定地址；若还需要「发给别人也能打开」的公开链接，
可保留 Cloudflare 隧道作为补充（但地址仍会变）。

