dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Run DeepSeek Harness Web UI on your home LAN — 4 minimal patches + one-click apply/revert scripts | 让 DeepSeek Harness 的 Web UI 在局域网跑起来
English | 简体中文
Run DeepSeek Harness Web UI on your home LAN — bind a specific IP, trust it, and open it from any device. 让 DeepSeek Harness 的 Web UI 在局域网里跑起来——从 Windows / 手机 / 平板直接打开。
🎯 目标版本:dsh
0.1.2-rc.1(commita66e470204) —— 补丁基于该版本编写并验证,其他版本可能失效(详见 🧩 兼容性)。
dsh 的 Web UI 官方只允许本机(localhost)访问。--host 0.0.0.0 直接报错:
error: --host 0.0.0.0 is intentionally not supported yet for safety:
it would expose remote code execution to the network; use 127.0.0.1 instead
这是有意为之的安全设计——dsh 的 Web UI 背后是一个能执行任意命令的 agent,官方不想让它裸奔到网络。
但家里/办公室的局域网,想在 Windows、手机、平板上打开 dsh 怎么办?本仓库提供 3 个最小补丁 + 一键脚本,让你绑定指定局域网 IP 安全运行 dsh Web UI。
--trusted-host CLI + rpc-host.ts 里的 trustedHosts 围栏,因此这些文件不再需要打补丁)apply.sh / revert.sh),自动检测、防重复应用0.0.0.0 通配符仍被拒绝;--trusted-host 显式信任机制保留pnpm run build、页面加载、API 调用、特权接口全通过unrun),pnpm run build 不会莫名失败核心顺序一句话:先装好 dsh 源码,再跑 apply.sh 打补丁——apply.sh 是打补丁工具,不是 dsh 安装器。
node -v 验证)pnpm -v 验证)git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
pnpm install
⚠️ 必须是 git clone 的源码,不能用
npm install装的成品包——补丁要改源码文件。 ⚠️ 不要用--depth 1浅克隆(后面固定版本需要完整历史)。当前 master 分支即目标版本
0.1.2-rc.1(commita66e470204)。若日后上游已前进(apply.sh会提示版本不匹配),先固定版本再继续:git checkout a66e470204 pnpm install
git clone https://github.com/oitsukiii/deepseek-harness-lan.git
cd deepseek-harness-lan
./apply.sh /path/to/deepseek-harness
apply.sh 自动完成:版本校验 → 检查能否干净应用 → 打补丁 → 补装构建依赖 unrun。看到 ✓ 补丁应用完成 即成功。
💡 目录无关:
deepseek-harness-lan和deepseek-harness可以放在任意目录(任意组合)——脚本自动定位自身 patch、按参数定位 dsh 仓库,无硬编码路径。三种运行方式任选:传 dsh 路径参数、cd到 dsh 目录再跑、或把 deepseek-harness-lan 放在 dsh 旁边。
cd /path/to/deepseek-harness
pnpm run build
randomUUID polyfill 在 web 产物里,必须重新构建才生效。
pnpm dsh web --host 192.168.1.100 --trusted-host 192.168.1.100
把 192.168.1.100 换成你的局域网 IP(ip addr 或路由器后台查看)。
在其他设备(Windows / 手机 / 平板)浏览器打开:
http://192.168.1.100:3080
⚠️ 若之前打开过,请 Ctrl + F5 强制刷新(浏览器可能缓存旧 JS)。
验证清单:
crypto.randomUUID is not a function./revert.sh /path/to/deepseek-harness
一键移除补丁,之后可正常 git pull 更新 dsh。
如果你不想改 dsh 源码(想保持官方原样、官方升级零维护),SSH 隧道是唯一干净的局域网访问方式——零补丁,三道闸天然全通。
dsh 的信任检查(browser-trust)看的是请求的 Host 头,不是来源 IP(DNS rebinding 防御);而 crypto.randomUUID 只在 secure context(HTTPS 或 localhost)可用。SSH 隧道让浏览器始终以 127.0.0.1 访问 dsh,于是:
| 三道闸 | SSH 隧道下 | 为什么 |
|---|---|---|
| 闸 1(CLI/schema) | ✅ 不触发 | dsh 监听 127.0.0.1 = 官方默认值,无需改动 |
| 闸 2(browser-trust) | ✅ 含特权接口 | Host 头 = 127.0.0.1 → loopback 豁免(原版特权接口也只放行 loopback) |
| 闸 3(randomUUID) | ✅ 可用 | 127.0.0.1 属于 secure context,浏览器原生提供 |
# 1. 按官方原样启动 dsh(不打补丁,监听 127.0.0.1:3080)
cd /path/to/deepseek-harness
pnpm dsh web
在需要访问的电脑上开隧道(Windows 10/11 自带 OpenSSH):
ssh -N -L 3080:127.0.0.1:3080 <user>@<NAS-IP>
浏览器打开:
http://127.0.0.1:3080
配置 API、特权接口、全部功能均可正常使用。
| 方案 | 改源码 | 电脑 | 手机/平板 | 官方升级 |
|---|---|---|---|---|
| SSH 隧道(本方案) | ❌ 零改动 | ✅ | ⚠️ 每台设备配隧道 | 直接 git pull,无感 |
| deepseek-harness-lan 补丁(主方案) | ✅ 4 处最小 diff | ✅ | ✅ 直接开网址 | 需重新打补丁 |
反代(无论 HTTP 还是 HTTPS)后 Host 头变成局域网 IP,而原版特权接口(settings.describe、llm.providers 等——配置模型 API 必需)是 isTrustedApiRequest(request, []) 强制只放行 loopback,所以配置 API 那步必然 403。SSH 隧道是唯一"不改源码且功能完整"的路径;想全设备直接开网址访问,就用主方案的补丁。
dsh 官方阻止局域网访问,一共有 三道闸。本项目的 3 个补丁逐个击破:
0.0.0.0,schema 只认两个字面量现象:--host 0.0.0.0 直接报错;想绑具体 IP(如 192.168.1.100)也会启动失败:
ValidationError: invalid config:
- $.host expected "127.0.0.1" | "0.0.0.0" but got "192.168.1.100" (at host)
原因(两层限制):
| 层 | 位置 | 限制 |
|---|---|---|
| CLI 层 | packages/bundle/web-app/src/startup.ts | options.host === '0.0.0.0' 时 program.error() 拒绝启动 |
| Schema 层 | packages/host/webserver/src/index.ts | zod 校验 z.union([z.const('127.0.0.1'), z.const('0.0.0.0')]),类型定义也只允许这两个值 |
补丁(packages/host/webserver/src/index.ts,放宽 schema):
- host: '127.0.0.1' | '0.0.0.0' // 类型
+ host: string
- host: z.union([z.const('127.0.0.1'), z.const('0.0.0.0')]).required() // zod
+ host: z.string().required()
📌 0.1.2-rc.1 说明:CLI 层(
startup.ts)的--host 0.0.0.0拒绝逻辑上游仍保留,但无需再补——它只拒绝通配符,不影响绑定具体局域网 IP;该文件不再出现在补丁中。
设计取舍:0.0.0.0 通配符绑定所有网卡(包括公网/WG),危险;绑定具体 IP 只暴露一个网卡,可控。所以只放开具体 IP,通配符继续拒绝。
现象:页面能打开,但所有 /api/* 请求返回 HTTP 403,例如:
加载提供方目录失败: transport failure for /api/llm.providers: HTTP 403
原因:dsh 的 /api 网关前有一道 browser-trust fence(防 DNS rebinding / 跨站攻击),packages/client/connection/src/index.ts 里:
// 信任列表:只有绑 0.0.0.0 时才自动采集所有局域网 IP
// 绑具体 IP 时列表为空 → 非 localhost 请求全 403
const lanAddresses = bindHost === ALL_INTERFACES_HOST ? collectLanIps() : []
return { lanAddresses, trustedHosts: [...lanAddresses, ...extra] }
另外,特权方法(settings.*、credentials.*、agentPreset.* 等)用的是空信任列表检查——意味着即使加了 --trusted-host,这些接口依然只放行 localhost:
if (PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, [])) {
return new Response('forbidden', { status: 403 })
}
补丁:0.1.2-rc.1 起无需补丁——本闸已被上游采纳。packages/client/connection/src/rpc-host.ts 现检查 this.trustedHosts(由 CLI 的 --trusted-host 配置)而非空列表,因此 --trusted-host 已对特权接口生效。本仓库因此不再修改 packages/client/connection/src/index.ts;补丁文件只覆盖其余 3 个文件。
设计取舍(上游采纳后的语义):--trusted-host(管理员显式配置的信任入口)对特权接口生效。不传 --trusted-host 时行为不变,仍只放行 localhost——官方安全语义原样保留。
crypto.randomUUID is not a function现象:配置 API 时报错:
加载提供方目录失败: crypto.randomUUID is not a function
原因:浏览器 Web Crypto API 的 crypto.randomUUID() 只在 secure context(HTTPS 或 localhost)可用。用 http://192.168.1.100:3080(局域网明文 HTTP)访问时,这个函数不存在。
补丁(apps/web/src/main.ts,Web 入口最前面):
// crypto.randomUUID 仅 secure context 可用;HTTP 局域网环境补一个 UUIDv4 实现
if (typeof globalThis.crypto === 'object' && typeof globalThis.crypto.randomUUID !== 'function') {
try {
globalThis.crypto.randomUUID = () =>
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0
const v = c === 'x' ? r : (r & 0x3) | 0x8
return v.toString(16)
})
} catch { /* crypto 只读环境则保持原样 */ }
}
💡 UUID 只用于本地标识(附件草稿、会话 id 等),不涉及安全校验,polyfill 无安全风险。
--host 0.0.0.0(补丁后依然被拒绝,这是有意保留的防线)。--trusted-host 是官方 browser-trust 机制的显式信任入口,请只填你自己的局域网 IP。本补丁针对 dsh 0.1.2-rc.1(commit a66e470204)编写并验证。
✅ 上游说明(0.1.2-rc.1):原 4 处 LAN 改动中有 2 处已被上游采纳——CLI 现已支持
--trusted-host,packages/client/connection/src/rpc-host.ts检查this.trustedHosts而非空列表——因此当前补丁集精简为 3 个文件:
packages/host/webserver/src/index.ts— 把绑定 host 的 schema 从两个字面量(127.0.0.1/0.0.0.0)放宽为string(支持局域网 IP);apps/web/src/main.ts— 明文 HTTP 局域网场景下的crypto.randomUUIDpolyfill;packages/client/tsdown.client.ts—REPOSITORY_ROOT改用process.cwd()而非import.meta.url(修复 tsdown 用unrun编译此 preset 到node_modules/.unrun时的工作区 manifest 查找,否则会报no packages/*/*/package.json declares the name …)。
⚠️ 上游已知构建怪癖(0.1.2-rc.1):干净 checkout 上跑完整
pnpm run build可能报Cannot find entry: ["lib/types/{index,invariant,startup}.js"](归因于@deepseek-ai/dsh-root)。原因:旧版 dsh 遗留目录(如packages/client/runtime、packages/host/apiproxy)已被上游删除,但git checkout不会清掉它们——因为里面只有被忽略的文件(node_modules)。修复:删除遗留目录(先用git clean -ndx <dir>列出,再删除),然后重新构建。
git apply --check)→ 完整 pnpm run build 成功 → Web UI 页面加载 → /api 接口调用 → 特权接口(settings.describe 等)全通过。apply.sh 的 git apply --check 会检查失败并安全中止,不会弄脏你的仓库(这是保护机制,不是 bug)。apply.sh,失败后记录冲突文件;revert.sh 一键还原,之后可正常 git pull 更新 dsh。一份补丁对应一个 dsh 版本线;更早/不同的版本可能 git apply --check 失败(这正是安全机制——失败即中止,不会弄脏你的仓库)。
| dsh 版本 | dsh 发布时间 | 我该用哪个补丁? |
|---|---|---|
0.0.1-rc.1(npm) | 2026-08-10 | — |
0.0.1-rc.2(npm) | 2026-08-11 | — |
0.0.1-rc.5(npm) | 2026-08-12 | — |
0.1.0-rc.2(npm) | 2026-08-13 | — |
0.1.0-rc.3(npm) | 2026-08-13 | — |
0.1.0-rc.6(npm) | 2026-08-13 | — |
0.1.0-rc.7(release) | 2026-08-17 | v0.1.1 |
0.1.0-rc.8(release) | 2026-08-19 | v0.2.0 |
0.1.1-rc.1(release) | 2026-08-21 | v0.2.0 |
0.1.1-rc.2(release) | 2026-08-21 | v0.2.0 |
0.1.2-rc.1(release) | 2026-08-29 | v0.3.0 ⭐ 当前(3 文件补丁;4 处 LAN 改动已有 2 处进入上游) |
💡 经验法则:rc.8 及以后的版本用当前补丁即可;rc.7 及更早需要用旧补丁或直接升级。早期版本(
0.0.1-rc.x、0.1.0-rc.2/3/6)是公开发布 3 天内的过渡版本,不应有人还在使用。
Q: 手机上能访问吗?
A: 能。只要手机连同一个局域网,浏览器打开 http://<NAS-IP>:3080 即可。
Q: 打补丁后 dsh 官方更新怎么办?
A: apply.sh 会先 git apply --check,上游代码变了会检查失败并中止,不会弄脏你的仓库。还原用 revert.sh,然后正常 git pull 更新即可。
Q: 为什么不用 Docker 跑? A: dsh 官方提供的是 Node.js / npm 包,无官方 Docker 镜像;本项目只改源码,直接沿用官方安装方式最稳。
Q: 这个补丁会被官方接受吗? A: 官方有意禁了通配符绑定,短期内不太可能放开;但绑定具体 IP + 显式信任的思路,可以给官方提 issue 讨论。
| 文件 | 解决 |
|---|---|
patches/deepseek-harness-lan.patch | 全部 4 处改动的统一 diff(git apply 直接用) |
MIT License — 与 DeepSeek Harness 官方无关的非官方社区项目,仅供学习与自用参考。