dsh-remote-access

August 16, 2026 · View on GitHub

DeepSeek Harness WebUI 的远程访问插件:在 DSH 本机 Web 服务前面启动一个带密码验证的反向代理网关,允许从局域网/远程访问 WebUI,同时保持 DSH 自身只监听 127.0.0.1

工作原理

  • DSH 官方出于安全考虑,当前不允许通过 --host 0.0.0.0 直接把 WebUI 暴露到网络。
  • 本插件不改动 DSH 的监听地址,而是额外启动一个 HTTP/WebSocket 反向代理:
    • 默认监听 0.0.0.0:3081
    • 所有请求先经过密码验证(登录 Cookie 或 HTTP Basic Auth);
    • 验证通过后转发到本机 DSH Web 服务(默认 127.0.0.1:<dsh port>);
    • 转发时把 Host / Origin 重写为本地回环地址,因此 DSH 自带的 /api 浏览器信任围栏可以正常放行,同时外部无法直接触达未鉴权的 DSH API。
  • WebSocket(会话事件、SSE 升级等)同样经过密码验证后再代理。

安装

# 在 deepseek-harness 仓库根执行
pnpm dsh plugin --profile web add ./dsh-remote-access
# 或从 npm/GitHub 安装后:
# pnpm dsh plugin --profile web add dsh-remote-access

安装后必须设置访问密码,再重启 dsh web。所有配置均从 DSH 配置文件读取,不再使用环境变量。

可以通过 DSH 设置界面的 “远程” 页设置密码,也可以在 profile 的 cordis.patch.yml--patch 覆盖层中配置:

- id: dsh-remote-access
  config:
    password: 'your-strong-password'
    remoteHost: '0.0.0.0'
    remotePort: 3081

设置密码

插件不再读取 DSH_REMOTE_ACCESS_PASSWORD 环境变量。密码只通过以下两种方式配置:

  1. DSH 设置界面 “远程” 页;
  2. profile 的 cordis.patch.yml--patch 覆盖层。

例如在 profile 配置文件中设置:

- id: dsh-remote-access
  config:
    enabled: true
    remoteHost: '0.0.0.0'
    remotePort: 3081
    password: 'your-strong-password'
    sessionTtlMs: 604800000
    maxSessions: 100

注意 config 是整块替换,需要重述全部键。通过设置界面保存的密码会加密后写入 DSH 的 settings.yaml

开发期加载

# 从 deepseek-harness 仓库根执行
pnpm dsh web --patch /abs/path/to/dsh-remote-access/cordis.yml

打开 http://<本机局域网IP>:3081,先看到登录页;输入密码后进入 DSH WebUI。

配置项

配置默认值说明
enabledtrue是否启动远程网关
remoteHost0.0.0.0远程网关监听地址;0.0.0.0 表示所有网卡
remotePort3081远程网关监听端口
targetHost127.0.0.1转发目标 DSH 地址
targetPort自动转发目标 DSH 端口;缺省使用当前 webServer 服务端口
password访问密码;为空且启用时远程网关不启动
enableCaptchafalse是否启用登录验证码
maxAttemptsPerDay20每个 IP 在 24 小时内最大失败登录次数
maxAttemptsPer5h10每个 IP 在 5 小时内最大失败登录次数
sessionTtlMs604800000登录 Cookie 有效期(毫秒,默认 7 天)
maxSessions100内存中最大并发会话数
titleDeepSeek Harness Remote Access登录页标题

设置界面

插件会在 DSH 设置界面新增一个 “远程” 页,可以修改:

  • 是否启用远程访问
  • 远程端口
  • 访问密码
  • 是否启用验证码
  • 每日登录尝试限额(24 小时)
  • 5 小时内登录尝试限额

该页面通过插件自己的 /plugins/dsh-remote-access/settings 路由读写配置,因此不依赖 DSH 的 apiproxy 设置白名单,适合作为外部插件分发。

用独立 profile 测试

不要直接改正在使用的 web profile;新开一个测试 profile:

# 1. 创建 profile 并加入本插件
dsh plugin --profile remote-access-test add /abs/path/to/dsh-remote-access

# 2. 如果该 profile 需要 WebUI,把 @deepseek-ai/dsh-web-app 加入
#    $DSH_HOME/profiles/remote-access-test/package.json 的 dsh.profile.bundles

# 3. 启动(端口按需修改;密码在配置文件中或设置界面中配置)
dsh --profile remote-access-test --port 8221

启动后:

  • DSH WebUI 本机地址:http://127.0.0.1:8221
  • 远程访问网关:http://<本机IP>:3081(先登录,再进入 WebUI)

验证

# 未认证请求应返回 401
curl -i http://127.0.0.1:3081/

# Basic Auth 可访问 DSH 页面/API
curl -u admin:'your-strong-password' http://127.0.0.1:3081/api/session.list

浏览器访问时,未登录会看到登录页;登录后 Cookie 会自动用于后续 HTTP 与 WebSocket 请求。

安全说明

  • 不要使用弱密码。远程暴露的是完整 DSH WebUI,包含 Shell/文件系统等 agent 能力,等同于远程代码执行面。
  • 密码不会明文写入 settings.yaml,保存时会使用 AES-256-GCM 加密;加密密钥保存在 $DSH_HOME/.dsh-remote-access.key。如果密钥丢失或密文损坏导致无法解密,插件会阻止所有登录,并在远程网关登录页显示警告。
  • 默认走 HTTP,密码和会话 Cookie 在网络上是明文传输。生产环境请在前面加 TLS 反向代理(如 Caddy/nginx),或自行扩展 HTTPS。
  • 会话只保存在进程内存中,DSH 重启后所有登录会话失效,需要重新登录。
  • 登录失败会按 IP 记录;超过每日或 5 小时限额后返回 429 Too Many Requests。验证码为一次性算术题,启用后每次登录都需要重新填写。
  • 本插件是“网关鉴权”,不替代 DSH 自身的权限模式。登录后获得的仍是 DSH 当前用户的权限。

文件结构

  • src/index.ts — Host 插件实现(反向代理 + 密码验证 + 设置路由)
  • src/client/ — 浏览器半(设置页“远程”)
  • tsdown.config.ts — Client bundle 构建配置
  • cordis.patch.yml — bundle 安装补丁
  • cordis.yml — 开发期 --patch 挂载
  • package.json / tsconfig.json — 构建配置