# dsh-tailscale-gateway
只让你选择的人私密访问 DSH Web,而不是向整个网络开放。
让指定的 Tailnet 用户通过浏览器私密访问本机 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)Web UI, 同时不把 DSH 暴露到局域网或公网。这个小巧、无运行时依赖的 DSH Web-profile bundle 让 DSH 与网关始终留在回环地址,并以 [Tailscale Serve](https://tailscale.com/docs/features/tailscale-serve) 作为唯一的远程入口。 ```text 白名单中的 Tailnet 浏览器 ─ HTTPS ─> Tailscale Serve │ └─ 识别身份的 gateway ─> 本机 DSH 127.0.0.1:3088 127.0.0.1:3080 ``` **它提供什么:** DSH 前面的一份精确 Tailscale login 白名单、仅回环的网关,以及 冲突安全的私有 Serve 设置。单独安装不会做任何事;引导式设置只会在确认后写入启用的 profile 条目,下一次 DSH Web 启动时才会激活。绝不会开启 LAN 监听器或配置 Funnel。 ## 为什么需要这个网关? Tailscale 提供的是已认证的网络连接;本 bundle 则把它变成一个范围明确、理解 DSH 特性的 访问边界: | 你需要的能力 | 本 bundle 的做法 | | --- | --- | | 只与指定的人共享 DSH | 精确允许 `Tailscale-User-Login` 身份,而不是让所有能抵达节点的 Tailnet 成员都能使用。 | | 让 DSH 始终留在本机 | DSH 和 gateway 都固定为 `127.0.0.1`;没有 LAN 监听器,也没有公网 Funnel 模式。 | | 在远程使用正常的 DSH Web | 保护并转发 UI、HTTP API 和 WebSocket 事件流,然后以固定的回环 origin 转发给 DSH。 | | 避免误改路由 | setup 推断节点所有者并选择安全的可用 HTTPS 端口;`ensure` 只创建自己缺失的那一条路由,遇到冲突或 Funnel 会拒绝。 | | 保留已有服务 | 它绝不 reset Serve、覆盖其他 handler,或自动删除任何路由。 | 结果很简单:安装、确认生成的计划、重启 DSH,然后打开 Tailscale URL。正常流程中无需另行 运行 `tailscale serve`。 ## 两条命令完成设置,然后重启 DSH 你需要一个正常工作的本地 DSH Web profile,以及已启用 MagicDNS 和 HTTPS 的非 tag Tailscale 节点。Node.js 20+ 通常由 DSH 提供。 1. **安装未启用的 bundle。** 这一步本身不会启动监听器,也不会更改 Tailscale。 ```sh dsh plugin --profile web add -w github:TiantianFlow/dsh-tailscale-gateway ``` DSH 的 Web profile 是 pnpm workspace root,因此必须使用 `-w`。 2. **运行引导式设置,并确认显示的计划。** 它会推断当前节点所有者的 Tailscale login 作为第一个白名单用户;你也可以在提示中替换它。 ```sh dsh plugin --profile web exec dsh-tailscale-gateway-setup ``` 你的确认会写入带有受保护 `tailscaleServe.mode: ensure` 的启用 profile 条目,也会选择 当前节点所有者作为第一个可信 login 并挑选安全、可用的 HTTPS 端口。现在请重启你自己 管理的 DSH Web 进程或服务。DSH 在启动时加载新安装的 bundle;setup 不会猜测、终止或 重启你的 supervisor。在那次启动中,插件可以保留精确匹配的私有路由,或创建并验证一条 缺失的、指向 `127.0.0.1:3088` 的根路由。它绝不运行 Funnel、reset 或 off,遇到冲突会 拒绝执行。 重启后,请从白名单中的 Tailscale 用户设备打开配置的 URL。这就是成功标准;3088 端口 本身仍不能从局域网或 tailnet 直接访问。使用 `--print` 可只预览不写入;已审阅的非交互 式运行可使用 `--yes`。 ### setup 之后 保存配置并不表示 URL 已经可用。请用你自己管理的进程管理方式重启 DSH Web。如果回环端口 被占用、Tailscale 不可用,或所选 Serve 路由有冲突,插件会在启动时失败关闭且不会改动无关 路由。解决该启动错误后,再次重启 DSH。 ## 谁可以使用? 设置会自动将**当前节点所有者**加入 `trustedLogins`。该精确的 Tailscale login 会在 重启后获得使用 DSH 的授权;设置不会把整个 tailnet 的成员都加入。 | 层级 | 决定什么 | 对其他 tailnet 用户的默认结果 | | --- | --- | --- | | `trustedLogins`(必需) | 此已验证的 Tailscale 身份能否使用 DSH? | 网关返回 **403**,不会把请求转发给 DSH。 | | Tailnet ACL/grant(可选) | 此人的网络连接能否抵达 Serve 端点? | 除非 tailnet policy 阻止,否则可能抵达端点。 | 换句话说,可选的 Tailnet grant 是**网络可达性**的纵深防御,并不授权使用 DSH。没有 grant(且没有其他限制性 Tailnet policy)时,不在白名单中的 tailnet 用户能够抵达端点, 但网关会识别其 Tailscale 身份并返回 403。没有匹配的 `trustedLogins` 条目,他们无法 使用 DSH。 若要有意地共享 DSH,请编辑生成的 Web-profile 条目并添加每个人精确的 Tailscale login。每位白名单中的人都是完整的 DSH 管理员;请使用 Tailscale 管理控制台显示的 login identity,而不是显示名称。修改生成的条目后,请重启你自己管理的 DSH Web 进程。 ```yaml - insert: - id: dsh-tailscale-gateway-user-instance name: dsh-tailscale-gateway config: trustedLogins: - 'owner@example.invalid' - 'another-admin@example.invalid' ``` ## 可选:同时限制 Tailnet 的网络可达性 网关白名单始终是必需的。如果你还希望 tailnet 自身阻止非管理员抵达端点,请添加一条 范围很窄的 Tailnet policy。下面是一个通用 [grant](https://tailscale.com/docs/reference/syntax/grants) 示例;请替换组成员、网关的 Tailscale IP 和所选 HTTPS 端口。 ```hujson { "groups": { "group:dsh-admins": ["admin@example.invalid"], }, "hosts": { "dsh-gateway": "100.64.0.10", }, "grants": [ { "src": ["group:dsh-admins"], "dst": ["dsh-gateway"], "ip": ["tcp:8443"], }, ], } ``` grant 是叠加的:已有的更宽泛规则仍可能允许网络连接。若希望 Tailnet policy 自身也具 限制性,请审查重叠规则。grant 或 ACL 都不能替代 `trustedLogins`。 ## 高级:手动配置 大多数人应使用引导式设置。只有当你需要不同的所有者/login、指定的规范 URL,或想 自行管理 Serve 时,才需要本节。完整的净化模板在 [examples/web-profile.patch.yml](examples/web-profile.patch.yml);它是可兼容旧安装的启动时 baseline 示例。引导式设置会为你生成同样安全的启用条目。 启用状态下常规配置只接受 `publicOrigin`、`trustedLogins` 和可选的 `tailscaleServe`。 引导式设置还会写入一个不透明的 `activationToken`,仅保留给回环本机诊断协议使用,不是 远程认证;请保留它且不要分享生成的 profile。监听器、上游、TLS、OAuth、secret 和未知 键会被拒绝。`publicOrigin` 必须是用户实际打开的、仅含 origin 的 HTTPS `*.ts.net` URL; login 必须精确匹配且区分大小写。 ### 其他安装方式 快速开始使用 GitHub。若要从源码 checkout 进行开发: ```sh git clone https://github.com/TiantianFlow/dsh-tailscale-gateway.git cd dsh-tailscale-gateway dsh plugin --profile web add -w "$PWD" ``` 若未来发布 npm 版本,则等效的安装方式为: ```sh dsh plugin --profile web add -w dsh-tailscale-gateway ``` ### 让插件管理它唯一的路由 这是 setup 生成的模式。公开 HTTPS 端口从 `publicOrigin` 推导;不要重复配置该端口。 ```yaml - id: dsh-tailscale-gateway config: enabled: true publicOrigin: 'https://your-device.your-tailnet.ts.net:8443' trustedLogins: - 'replace-with-an-exact-tailscale-login@example.invalid' tailscaleServe: mode: ensure ``` DSH 启动且 sidecar 绑定后,`ensure` 会通过 argv 形式的本机 Tailscale 命令(绝不使用 shell)检查 `serve status --json`。它只创建一条缺失且精确地指向 `http://127.0.0.1:3088` 的根路由,并会验证结果;它不会覆盖其他 handler 或端口。 它绝不运行 `funnel`、`reset` 或 `off`。 ### 自行管理 Serve 如果你想完全拥有路由管理权,请省略 `tailscaleServe` 或设为 `mode: manual`。在 DSH 启动回环 sidecar 后,请自行创建相匹配的私有路由。此处外部 URL 和命令都使用 8443 端口: ```yaml tailscaleServe: mode: manual ``` ```sh tailscale serve --https=8443 --bg http://127.0.0.1:3088 tailscale serve status --json ``` 请勿用 `tailscale funnel` 代替:Funnel 是公开的,并且不会提供本网关所需的身份请求头。 除非你确实要删除节点上的所有 Serve 路由,否则也不要使用 `tailscale serve reset`。 ## 它保护什么,以及不保护什么 - 监听器固定为 `127.0.0.1:3088`;唯一的上游固定为 `127.0.0.1:3080`。 - 它要求恰好一个由 Tailscale 注入的 `Tailscale-User-Login` 请求头、精确的外部 `Host`,以及对不安全请求、`/api` 请求和 WebSocket upgrade 的精确外部 `Origin`。 - 转发前会移除浏览器凭据、客户端提供的 proxy/Tailscale 请求头和 hop-by-hop 请求头, 然后把上游 `Host` 与 `Origin` 改写为回环地址。 - 它不提供 TLS 监听器、cookie/session 存储、OAuth/OIDC 流程、Cloudflare 依赖、DSH core patch、直接局域网监听器或公网监听器。 Tailscale Serve 在把请求发送给本地后端前,会将调用方伪造的身份请求头替换为已认证 用户的身份。因此网关必须始终只监听回环地址。同一主机上的进程理论上能伪造回环请求, 但它本来就与 DSH 处于同一台本机的信任边界内。tag 设备和 Funnel 流量不会提供可用的 用户 login identity,因此会被拒绝。 ## 运维 若要停止远程访问但保留 bundle,请在生成的 user-instance profile 条目中设定 `enabled: false`,然后重启你自己管理的 DSH Web 进程。私有 Serve 路由会刻意保留; 只有确定要丢弃该路由时才单独移除它: ```sh tailscale serve --https=8443 off ``` 卸载前,请移除 setup 生成的整个顶层 `- insert:` 区块(或保持其禁用),重启 DSH, 然后再移除软件包: ```sh dsh plugin --profile web remove -w dsh-tailscale-gateway ``` 移除 bundle 绝不会自动删除持久的 Tailscale Serve 路由——即使该路由由 `ensure` 创建也 一样。为保持兼容,软件包仍保留面向旧安装的禁用 baseline `id: dsh-tailscale-gateway`;setup 不会替换或迁移该条目。DSH 仍可能隐藏仅限本地交互的 控件;本网关只传输常规的 DSH UI/API,不会改变 DSH 的产品策略。 ## 开发 ```sh pnpm install --frozen-lockfile pnpm run check pnpm test pnpm audit --prod npm pack --dry-run ``` 贡献说明见 [CONTRIBUTING.md](CONTRIBUTING.md),私密漏洞报告方式见 [SECURITY.md](SECURITY.md),社区行为准则见 [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)。 维护者可参考 [RELEASING.md](RELEASING.md) 了解未来版本的发布指引。 ## 社区 感谢 [LINUX DO](https://linux.do/) 为中文开发者提供交流想法和反馈的空间。本致谢不 代表任何隶属关系或官方背书。 ## 许可证 [MIT](LICENSE)