Mzy123l/dsh-plugin-remote-access ↗★ 2
dsh-plugin-remote-access
Expose this machine's DSH web GUI to a chosen CIDR range (e.g. Tailscale), with an optional numeric access code, a phone layout that only affects remote pages, and the official UI preferences stored in this plugin's own config. 适合需要通过手机或异地设备远程访问、控制本地DSH服务的用户。
インストール
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:Mzy123l/dsh-plugin-remote-accessドキュメント
README 全文を読む ↗使用
方式一:设访问密码(推荐,手机不用复制长串)
- 「设置 → 远程访问 → 访问密码」填 4–12 位数字或字母,保存(写别的字符会被就地拦下并说明规则)。
- 手机打开
http://:/—— 地址和端口见状态文件里的手机访问:那一行。 - 输一次密码即可进入,之后 30 天免密(cookie)。
- 密码输错一次,该地址就自动写进「排除的网段」(形如
100.x.y.z/32)、之后一律403; 解封 = 到「设置 → 远程访问 → 排除的网段」里把那一项删掉。
方式二:用带令牌的网址(不设密码)
打开状态文件里的 远程访问网址: http://…/?token=… 一次,DSH 会把 token 换成自己的签名
cookie(默认 30 天);之后直接访问 http://:/ 即可。没票就是 401。
每次启动 DSH 都会换一张 token(用另一个 Windows 账户跑 DSH,也有它自己的一张),所以旧网址、 别的账户/上一次运行留下的网址里那个
?token=…已经作废。拿它访问不会再把 DSH 那句英文甩给你了: 从当前版本起会看到插件自己的中文说明页(讲清「票作废」还是「没带票」,以及去哪儿拿当前那条)。 省事的做法:设了accessCode就直接打开裸地址 (http://:/)输一次密码;没设就复制状态文件里当前那条带票网址。 旧 cookie 同理不通用(DSH 的 cookie 绑hostname:port)。
状态文件
\remote-access-url.txt(默认在 %USERPROFILE%\.dsh,权限 0600)里写着:带票网址、
手机访问地址、是否开启了解锁密码、已拉黑的地址与「待补写」的地址、放行密钥、当前生效的配置、
上游自检结果。打不开时先看它。
⚠️ 文件里有访问令牌,等于本机操作权限,不要外传(访问密码在里面打码成
***)。
配置
设置页里能改的
「设置 → 远程访问」里是 8 个常用项(启用 / 允许的网段 / 排除的网段 / 端口 / 并发上限 / 日志级别 /
访问密码 / 远程UI布局),外加一层可折叠的下一级菜单 「UI 设置」(5 项界面偏好,见下)。
保存会写进 profile 的 cordis.patch.yml,插件随即热重载(端口会变,新网址以状态文件为准)。
访问密码的规则
访问密码只收 4–12 位数字或字母(大小写敏感)。写别的(空格、符号、太短太长)不会生效,
而且一定看得见:设置页点保存时就地拦下并说明规则,cordis.patch.yml 里手写的非法值会在
状态文件的诊断里留一条 「访问密码」没生效…。这条提示是故意做的 —— 静默失效会让人以为密码设好了,
然后在手机上撞见 DSH 那句英文 401(这曾经是最难查的一种「坏了」)。
改密码不会把已经进来的设备踢下线:放行 cookie 的密钥与 accessCode 无关,单独存在
\remote-access-secret(0600),DSH 重启后也照样有效。想让所有设备重新输一次密码,
删掉那个文件即可。
手机上的同一页也能改
DSH 的客户端策略让 configForms 在非回环页面不可写,但 Remote 通道本身是通的,
所以那一页直接调 ctx.remote.settings.describe() / mutate(),写盘跑在 Host 网关自己的上下文里,
落盘位置与桌面完全相同,而且等写盘完成才回执。
「UI 设置」这一组是什么、为什么要有副本
设置页里「远程访问」下面有一层可折叠的下一级菜单「UI 设置」,放的是官方「通用设置」里的五项界面偏好 (外观、字号大小、工作步骤展示、显示代码工作视图、性能与用量)。
官方这几项在非回环页面上只能「本页有效、刷新即还原」:ui-settings 把设置通道的持久化降级成内存态
(persistence = ctx.remote.$host.isLoopback ? 'host' : 'memory'),读写都到不了宿主 —— 手机端在官方设置里
改完,一刷新就回到默认。本插件因此存了同一批值,并在每次打开远程页面时重新套一遍(桌面端改完、
手机切回来也会重读):
- 用的是官方自己的「本页」写入入口(
theme.setTheme/theme.setFontSize/configForms.developerTools.setEnabled/ 官方那两行设置项的setTranscriptView、setPerformanceUsage), 与你在设置页手点那几行是同一条路径; - 宿主的官方配置一个字都不写;本机(回环)页面一个像素都不动(与
remoteLayout同一条硬约束); default(出厂值)不是「什么都不做」,而是显式套回官方默认值 —— 这样从「完全展开」改回「出厂值」 也能真的还原。官方默认值取自官方源码:外观system、字号14、工作步骤展示 Web 端detailed(桌面客户端standard)、显示代码工作视图true、性能与用量detailed;- 因此本插件的配置优先:在官方「通用设置」里改这几项只对当前页面有效,下一次重读配置时会被本插件的值 覆盖。想用官方的默认行为,就把这几项留在「出厂值」;
- 这一组是新增的 Host 配置字段,而宿主的配置 schema 是在 DSH 启动时读进来的:第一次升级到这一版需要重启 一次 DSH(之后改值、保存都不必重启;浏览器半区刷新页面即可生效)。
其余参数
其余参数只在 cordis.patch.yml 里配(也不建议常用):
| 键 | 默认 | 说明 | 设置页 |
|---|---|---|---|
enabled | true | 关掉它只需设 false,不必卸载 | ✅ |
allowCidrs | ['100.64.0.0/10'] | 允许来访的网段;也是 listen: auto 挑选本机监听地址的依据 | ✅ |
denyCidrs | [] | 白名单里的例外黑名单;输错访问密码的地址会自动加到这里,删掉该项即解封 | ✅ |
port | 0 | 监听端口,0 = 系统随机 | ✅ |
maxConnections | 64 | 并发连接上限(浏览器会开好几条 keep-alive,别设太小) | ✅ |
logLevel | 'info' | silent / info / debug | ✅ |
accessCode | '' | 解锁密码(4–12 位数字或字母)。设了就不用复制 token:手机开裸地址输一次即可;输错一次即把该地址写进「排除的网段」 | ✅ |
remoteLayout | 'auto' | 远程页面的界面布局:auto(按视口/指针自动判断)/ phone(强制手机布局,横竖屏自适应)/ desktop(与桌面一致)。只作用于远程页面 | ✅ |
remoteTheme | 'default' | 「UI 设置」一组里的外观:default(出厂值)/ dark(深色)/ light(浅色)/ system(跟随系统)。只作用于远程页面,且不写宿主设置文档 | ✅ |
remoteFontSize | 0 | 正文字号(10–22 px):0 = 出厂值(14) | ✅ |
remoteTranscriptView | 'default' | 工作步骤展示:default / compact(简洁)/ standard(标准)/ detailed(详细)/ verbose(完全展开) | ✅ |
remoteDeveloperTools | 'default' | 显示代码工作视图:default(出厂值=开启)/ on / off | ✅ |
remotePerformanceUsage | 'default' | 性能与用量:default / compact(简洁)/ detailed(详细) | ✅ |
listen | ['auto'] | auto = 只监听上面网段里的本机地址;也可写 ['100.x.y.z'] | — |
upstream | 'auto' | DSH 界面地址;auto 读 ctx.webServer.port | — |
rewriteHost | true | 把 Host/Origin 改写成上游 authority | — |
forwardClientHeaders | true | 转发 x-forwarded-for / x-forwarded-proto | — |
timeoutMs | 0 | 等上游响应头的超时(毫秒),0 = 不超时。响应头一到就交棒,正文/流式传输不会被它掐断 | — |
allowWebSocket | true | 透传 WebSocket(界面实时推送靠它) | — |
urlFile | '' → /remote-access-url.txt | 状态文件写哪;off = 不写 | — |
printUrl | true | 同时把带票网址打到 DSH 日志 | — |
banFile | '' → 与状态文件同目录的 remote-access-bans.txt | 拉黑暂存文件:只有「写进排除的网段」失败时才用得上,平时不用碰 | — |