---
title: "Portal Gateway：一次设备共享"
description: "主动启用 portal 设备共享，为选定的本机和远程应用提供入口，每次请求检查 people 授权。"
url: "https://tslink.md/zh/docs/portal-gateway"
locale: "zh"
product_version: "0.2.0"
source: "https://github.com/anydoor7/tslink/blob/v0.2.0/docs/portal.md"
---

> Documentation index: https://tslink.md/zh/llms.txt · Installed binary is authoritative: `tslink manifest`.

要让 tailnet 之外的人访问一个或多个私有应用，可启用 TSLink gateway 模式、添加应用路由，再向其实际 Tailscale 登录账户授予有期限的权限。对方必须安装 Tailscale、登录并接受一次 portal 节点设备共享；后续路由应用的授权变更无需再次邀请。网络策略必须允许连接。Gateway 模式需主动启用；**默认仍逐应用分享**。

同一批人需要多个私有 HTTP 或文件应用，且应用集合会变化时，可以使用 gateway。需要独立主机名和 cookie 时，保留默认逐应用分享。Gateway 路由共用一个主机名，每个应用使用独立 HTTPS 端口，并保留应用根路径。端口对应不同浏览器 origin，但**不隔离 cookie**：应用可能使用冲突的 cookie 名称，或设置影响其他端口的 cookie。目前没有 cookie 命名空间。TCP、公共 Funnel 和浏览器访客链接应用不能作为 gateway 路由。

## 启用并路由本机应用

```bash
tslink portal enable --owner you@example.com --gateway
tslink portal route add photos
tslink add notes --proxy localhost:3000 --portal-only
tslink add files --dir /srv/shared --portal-only --portal-port 8445
tslink portal route list --json
tslink status --urls
```

`photos` 必须已是私有 HTTP/文件应用；添加路由会保留其独立节点。新的 `--portal-only` 应用没有应用节点。私有主页监听 443，每个路由应用使用独立 HTTPS 端口，默认从 8443-8499 分配。使用 status 或 `tslink url notes --wait` 返回的准确 URL，例如 `https://home.example.ts.net:8443/`，不要猜主机名或端口。新启用的节点可能需完成入网才能就绪。

```bash
tslink portal route add photos --port 8447
```

重新添加时省略 `--port` 会保留已分配端口。`tslink portal route remove photos` 只删除该路由。Portal-only 应用必须保留路由；如需移除应用，改用 `tslink remove notes`。用 `tslink portal enable --owner you@example.com --gateway --gateway-ports 9000-9099` 选择端口范围，现有路由端口必须仍在范围内。

不带 gateway 选项的 enable 会保留现有 gateway。单独 `--gateway` 保留范围和标签；范围/标签选项必须搭配 `--gateway`。移除全部路由后，用 `tslink portal enable --owner you@example.com --gateway=false` 显式关闭 gateway 模式。`tslink portal disable` 关闭主页和全部路由，但保留配置和入网状态。Portal 拒绝公共 Funnel。

## 向一个人分享 gateway

```bash
tslink people add alice@example.com --apps photos,notes,files --for 7d --invite --print-links --qr
tslink people update alice@example.com --apps notes,files --for 7d
tslink people update alice@example.com --invite
```

创建邀请需要已存储的用户拥有的 Tailscale API token；OAuth client token 不能创建设备邀请。请自行发送生成的消息。`--print-links` 会显示 bearer 链接，需妥善保密。对于路由应用，TSLink 每人记录一个 gateway 设备邀请；后续路由应用授权变更无需新邀请。所选非路由应用仍需各自共享，并产生警告。应用直连 URL 保留独立设备共享和访问检查。普通二维码/手机指南指向 gateway 主页；邀请二维码使用 `--qr-invite @gateway`，搭配 `--invite --print-links` 及 `--qr` 或 `--qr-png`。

即使未启用 gateway，`list`、`status`、`add` 也会为 people-scoped 应用报告 `allow.mode: people`。撤销阻止后续请求；已接受的流可能继续。移除人员时先保存本地拒绝，再尝试撤销待接受的 gateway 邀请。已接受的设备共享可能保留，但无法绕过本地拒绝。通过设备共享接入的外部访客不会获得仅 tailnet 成员可用的访问申请表单。

## 路由其他主机上的应用

```bash
tslink portal enable --owner you@example.com --gateway --gateway-tag tag:gateway
tslink add media --remote https://mini.example.ts.net:9443 --portal-port 8446
```

`--remote https://<node>.<tailnet>.ts.net` 创建 portal-only HTTPS 代理。LocalAPI 必须实际报告 gateway 已带标签，只有配置值不够。`--gateway-tag` 需要凭据；零凭据 gateway 支持本机应用。远程应用必须在自身策略中允许 gateway 标签（TSLink 应用需显式 tag allow list）。注册不会编辑远端 ACL 或注册信息。

远程目标必须是 gateway 实际观察到的 tailnet 后缀内的 peer MagicDNS 名称，默认端口为 443。HTTP、IP 字面值、URL 凭据、fragment 和外部后缀一律拒绝；不支持 `.ts.net` 之外的自定义控制服务器域名。在路由激活、新建上游连接和健康探针时检查 peer 身份；每次请求重新检查标签和 tailnet 后缀。请求和探针通过 gateway 自身 netstack 连接 peer 的 Tailscale IP，不经宿主网络或解析器，TLS 仍验证注册主机名。

远端主机认证 gateway 节点本身。**远程应用不会收到访客身份 header 或转发的访客 IP**；需要区分具体人的应用必须保留自身登录。本机上游接收经过验证的访客 Tailscale 身份 header。这是显式注册远程目标，不是多主机发现或汇总清单。

## 连接与请求检查

每个连接都需在五秒内成功完成 WhoIs，之后才进行 TLS。获准使用任一路由应用的调用者可在另一条路由完成 TLS，但 HTTP gate 会拒绝其无权使用的应用。陌生人及仅获授非路由应用的人，在路由端口收不到 TLS 字节。每次 HTTP 请求和 WebSocket upgrade 都重新执行 WhoIs、registry 验证及 people 决策；registry 失败时拒绝访问。Tailscale 网络策略和后端认证仍适用。

浏览器 fetch、表单和 WebSocket upgrade 默认必须同源，包括 HTTPS scheme、主机名和端口。允许顶层 GET/HEAD 导航；没有 Origin/fetch metadata 的非浏览器请求仍需通过身份检查。`tslink portal route add photos --allow-cross-origin` 会主动减弱浏览器请求边界；同属 tailnet 不是启用理由。端口不提供 cookie 隔离。

## 健康与访问证据

Portal-only 代理/文件应用无需访客流量也会定期检查。远程检查使用相同的 tagged tsnet 传输。未配置 HTTP 状态范围时接受 200-399，不跟随重定向；401/403 需显式范围。意外响应保持 `degraded`，不触发 `app_down` 或“离线起始时间”；只有不可达后端在连续三次失败后成为 `down`。观察超过两倍间隔加超时后为 `unknown`。后端健康不能证明访客可达性。请使用[健康设置](https://tslink.md/zh/docs/health-and-alerts.md)和 `tslink health set notes --path /health`，避免用 `add` 替换整个应用。

`status` 和 `doctor` 的 `portal.gateway` 报告观察到的持久性、标签、NodeID、所有权证据、范围、路由状态和本次运行的 `dropped` 连接计数。连接丢弃日志按 gate 限频；主页使用 `@portal` 标记。计数包含因限频省略的丢弃。请求事件保留应用名，增加 `via: portal` 和稳定 reason。

| Reason                            | 含义                                                   |
| --------------------------------- | ---------------------------------------------------- |
| `remote_upstream_requires_tag`    | 未观察到 gateway 实际带标签                                   |
| `remote_upstream_outside_tailnet` | 远程主机不在观察到的后缀内                                        |
| `remote_upstream_not_peer`        | 注册主机不在 gateway 的 peer map 中                          |
| `upstream_down`                   | 上游失败，包括复用连接时远程信任检查失败                                 |
| `client_canceled`                 | 代理期间、响应 header 前客户端离开；allowed，状态码 499                |
| `route_closed` / `node_closed`    | TSLink 拆除路由/节点时中断请求；allowed，header 前为 503，之后保留已转发状态码 |

识别身份期间取消不产生事件。响应 header 后取消保留已转发状态码。真实后端故障增加 `error_class`：`connection_refused`、`connection_reset`、`tls`、`timeout` 或 `other`。保留范围、丢弃和崩溃缺口见[访问历史](https://tslink.md/zh/docs/access-history.md)。

## 恢复 stale 邀请

Gateway 在凭据和交互入网路径上均持久化。路由、授权、owner/admin 和端口范围编辑保留共享节点。启用/禁用、主机名/标签编辑，或 daemon 重启时的凭据模式/control URL 变化可能替换节点。NodeID 变化产生 `gateway_node_identity_changed`；旧节点的已接受共享不能转移。

先用 `tslink doctor --json` 和 `tslink status --json` 证明新 gateway 已运行、持久化且有所有权证据。比较 `tslink people list --json` 中活跃邀请的 `node_id` 与 `portal.gateway.node_id`。Stale 活跃尝试使 `people update --invite` 返回 `complete: false` 和 `gateway_invite_stale`。

```bash
tslink people update alice@example.com --invite --replace-invite @gateway=12345
```

将 `12345` 替换为记录的旧 ID。该操作把 stale 本地尝试（包括已接受共享）退役为 `target_gone`，允许为当前 gateway 创建邀请，但不会撤销旧远程共享。没有记录 ID 的 stale pending/sending/unknown 尝试需显式执行 `tslink people update alice@example.com --invite --reconcile-invite @gateway=none`；以后重试用普通 `--invite`。接收者必须接受新设备邀请。身份变化警告作为历史保留；已恢复的 `target_gone` 记录无需再次替换。不要跨节点复制入网 marker。完整流程见 [TSLink v0.2.0 人员指南](https://github.com/anydoor7/tslink/blob/v0.2.0/docs/people.md#gateway-or-per-app-invitations)。

## Registry schema 与降级

Gateway 配置使用 **registry schema 3**。现有 registry 在使用 gateway 配置前保留原版本；旧 reader 拒绝 schema 3。降级前：

1. 停止新 daemon，备份 registry 和 portal 状态。托管服务按[验证停止](https://tslink.md/zh/docs/daemon.md#verified-shutdown)操作。
2. 使用 v0.2.0，明确移除或替换 portal-only 和 remote 应用，移除全部路由，再关闭 gateway 模式。
3. 记录过的 gateway 邀请即使在 gateway 关闭后也让 schema 保持 3。若仍存在记录，恢复启用 gateway 前的 registry 备份；此后的 people 和邀请变更将丢失。
4. 启动旧 daemon 前确认 guest 网络共享及授权预期。只替换二进制不构成降级。

完整传输、持久性、浏览器及 MCP 边界见 [TSLink v0.2.0 portal.md](https://github.com/anydoor7/tslink/blob/v0.2.0/docs/portal.md#gateway-mode-one-device-share-for-routed-apps)。
