🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

远程安全访问 oh-summy/dsh-remote-control

DeepSeek Harness
oh-summy9 天前有提交已提供中文文档扫描:含敏感能力

通过隧道与密码门,从任意地点安全访问本机服务

29.4/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/11/1 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查未通过:仓库根目录及浅层子目录均无 dsh 插件清单,无法用 dsh 插件安装命令安装。以下命令仍可尝试,但可能失败。
无法用 dsh 插件命令安装(仓库内无 dsh 插件清单)
git clone https://github.com/oh-summy/dsh-remote-control.git
按该仓库 README 的原生方式安装;若作者另行发布了 DSH 插件包,请以其文档为准

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · platform
装得上吗
作者未把包发布到 npm,只能用源码安装
插件本身没问题,是分发方式不同
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 9 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

仓库根目录及浅层子目录均无 dsh 插件清单,无法用 dsh 插件安装命令安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-remote-control(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/11 22:24:22

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 86 处,展示前 70 条)
  • 发起网络请求
    plugin/client-src/client.js:17
    return fetch(API_BASE + path, opts).then(async (res) => {
  • 写入剪贴板
    plugin/client-src/client.js:169
    if (copyBtn) copyBtn.onclick = () => { navigator.clipboard.writeText(st.url).then(() => flashOk(copyBtn)).catch(() => setMsg("复制失败:" )); };
  • 写入剪贴板
    plugin/client-src/client.js:347
    try { const r = await rcApi("/rc-api/reveal", { method: "POST" }); await navigator.clipboard.writeText(r.password); flashOk(q("#rc-copypw")); }
  • 发起网络请求
    plugin/client-src/client.js:435
    const j = await (await fetch(MARKET_INDEX, { signal: AbortSignal.timeout(6000) })).json();
  • 发起网络请求
    plugin/lib/client.js:24
    return fetch(API_BASE + path, opts).then(async (res) => {
  • 写入剪贴板
    plugin/lib/client.js:176
    if (copyBtn) copyBtn.onclick = () => { navigator.clipboard.writeText(st.url).then(() => flashOk(copyBtn)).catch(() => setMsg("复制失败:" )); };
  • 写入剪贴板
    plugin/lib/client.js:354
    try { const r = await rcApi("/rc-api/reveal", { method: "POST" }); await navigator.clipboard.writeText(r.password); flashOk(q("#rc-copypw")); }
  • 发起网络请求
    plugin/lib/client.js:442
    const j = await (await fetch(MARKET_INDEX, { signal: AbortSignal.timeout(6000) })).json();
  • 读取本地文件
    plugin/lib/index.mjs:74
    for (const p of candidates) if (p && existsSync(p)) return p;
  • 写入本地文件
    plugin/lib/index.mjs:104
    writeFileSync(join(RUN_DIR, "events.json"), JSON.stringify(events, null, 2));
  • 发起网络请求
    plugin/lib/index.mjs:168
    const res = await fetch(hook, {
  • 请求外部主机open.feishu.cn
    plugin/lib/index.mjs:183
    const tokenJson = await (await fetch("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal", {
  • 发起网络请求
    plugin/lib/index.mjs:183
    const tokenJson = await (await fetch("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal", {
  • 请求外部主机open.feishu.cn
    plugin/lib/index.mjs:200
    const sendJson = await (await fetch(`https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${receiveIdType}`, {
  • 发起网络请求
    plugin/lib/index.mjs:200
    const sendJson = await (await fetch(`https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${receiveIdType}`, {
  • 读取本地文件
    plugin/lib/index.mjs:268
    return JSON.parse(readFileSync(join(RUN_DIR, "secrets.json"), "utf8"));
  • 写入本地文件
    plugin/lib/index.mjs:285
    writeFileSync(join(RUN_DIR, "secrets.json"), JSON.stringify(all, null, 2), { mode: 384 });
  • 写入本地文件
    plugin/lib/index.mjs:287
    chmodSync(join(RUN_DIR, "secrets.json"), 384);
  • 读取本地文件
    plugin/lib/index.mjs:292
    const m = readFileSync(join(homedir(), ".dsh", ".credentials.yaml"), "utf8").match(/client-connection browser-session:[ ]{0,500}?secret: *["']?([
  • 请求外部主机open.feishu.cn
    plugin/lib/index.mjs:495
    out.imChat = (await (await fetch("https://open.feishu.cn/open-apis/im/v1/chats?page_size=1", {
  • 发起网络请求
    plugin/lib/index.mjs:495
    out.imChat = (await (await fetch("https://open.feishu.cn/open-apis/im/v1/chats?page_size=1", {
  • 请求外部主机open.feishu.cn
    plugin/lib/index.mjs:501
    const j = await (await fetch("https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id", {
  • 发起网络请求
    plugin/lib/index.mjs:501
    const j = await (await fetch("https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id", {
  • 请求外部主机open.feishu.cn
    plugin/lib/index.mjs:583
    const chatsJson = await (await fetch("https://open.feishu.cn/open-apis/im/v1/chats?page_size=50", {
  • 发起网络请求
    plugin/lib/index.mjs:583
    const chatsJson = await (await fetch("https://open.feishu.cn/open-apis/im/v1/chats?page_size=50", {
  • 读取本地文件
    plugin/lib/index.mjs:637
    let found = p !== name && existsSync(p);
  • 执行外部命令来自配置/变量
    plugin/lib/index.mjs:639
    if (found) version = (spawnSync(p, ["--version"], {
  • 执行外部命令固定命令
    plugin/lib/index.mjs:643
    else found = spawnSync("which", [name], { encoding: "utf8" }).status === 0;
  • 执行外部命令固定命令
    plugin/lib/index.mjs:730
    return (spawnSync("ps", [
  • 读取本地文件
    plugin/lib/index.mjs:742
    return Number(readFileSync(join(RUN_DIR, name + ".pid"), "utf8").trim());
  • 读取本地文件
    plugin/lib/index.mjs:751
    const lines = readFileSync(PROFILE_PATCH, "utf8").split("\n");
  • 写入本地文件
    plugin/lib/index.mjs:820
    writeFileSync(SETTINGS_FILE, JSON.stringify(s, null, 2));
  • 删除本地文件
    plugin/lib/index.mjs:832
    rmSync(join(RUN_DIR, name + ".pid"));
  • 写入本地文件
    plugin/lib/index.mjs:841
    writeFileSync(caddyfile, renderCaddyfile());
  • 执行外部命令来自配置/变量
    plugin/lib/index.mjs:842
    caddyChild = spawn(findBinary(cfg, "caddy"), [
  • 写入本地文件
    plugin/lib/index.mjs:860
    writeFileSync(join(RUN_DIR, "caddy.pid"), String(caddyChild.pid));
  • 执行外部命令来自配置/变量
    plugin/lib/index.mjs:888
    cloudflaredChild = spawn(findBinary(cfg, "cloudflared"), [
  • 删除本地文件
    plugin/lib/index.mjs:974
    rmSync(join(RUN_DIR, f));
  • 删除本地文件
    plugin/lib/index.mjs:1129
    rmSync(join(RUN_DIR, f));
  • 读取本地文件
    plugin/src/index.ts:93
    for (const p of candidates) if (p && existsSync(p)) return p;
  • 写入本地文件
    plugin/src/index.ts:126
    try { writeFileSync(join(RUN_DIR, "events.json"), JSON.stringify(events, null, 2)); } catch { }
  • 发起网络请求
    plugin/src/index.ts:172
    const res = await fetch(hook, {
  • 请求外部主机open.feishu.cn
    plugin/src/index.ts:185
    const tokenRes = await fetch("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal", {
  • 发起网络请求
    plugin/src/index.ts:185
    const tokenRes = await fetch("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal", {
  • 请求外部主机open.feishu.cn
    plugin/src/index.ts:203
    const sendRes = await fetch(`https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${receiveIdType}`, {
  • 发起网络请求
    plugin/src/index.ts:203
    const sendRes = await fetch(`https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${receiveIdType}`, {
  • 读取本地文件
    plugin/src/index.ts:255
    try { return JSON.parse(readFileSync(join(RUN_DIR, "secrets.json"), "utf8")); }
  • 写入本地文件
    plugin/src/index.ts:272
    writeFileSync(join(RUN_DIR, "secrets.json"), JSON.stringify(all, null, 2), { mode: 0o600 });
  • 写入本地文件
    plugin/src/index.ts:273
    try { chmodSync(join(RUN_DIR, "secrets.json"), 0o600); } catch { }
  • 读取本地文件
    plugin/src/index.ts:279
    const yaml = readFileSync(join(homedir(), ".dsh", ".credentials.yaml"), "utf8");
  • 请求外部主机open.feishu.cn
    plugin/src/index.ts:460
    const r = await fetch("https://open.feishu.cn/open-apis/im/v1/chats?page_size=1", { headers: { Authorization: "Bearer " + token }, signal: AbortSignal
  • 发起网络请求
    plugin/src/index.ts:460
    const r = await fetch("https://open.feishu.cn/open-apis/im/v1/chats?page_size=1", { headers: { Authorization: "Bearer " + token }, signal: AbortSignal
  • 请求外部主机open.feishu.cn
    plugin/src/index.ts:464
    const r = await fetch("https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id", {
  • 发起网络请求
    plugin/src/index.ts:464
    const r = await fetch("https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id", {
  • 请求外部主机open.feishu.cn
    plugin/src/index.ts:538
    const chatsRes = await fetch("https://open.feishu.cn/open-apis/im/v1/chats?page_size=50", {
  • 发起网络请求
    plugin/src/index.ts:538
    const chatsRes = await fetch("https://open.feishu.cn/open-apis/im/v1/chats?page_size=50", {
  • 读取本地文件
    plugin/src/index.ts:586
    let found = absolute && existsSync(p);
  • 执行外部命令来自配置/变量
    plugin/src/index.ts:589
    const r = spawnSync(p, ["--version"], { encoding: "utf8", timeout: 4000 });
  • 执行外部命令固定命令
    plugin/src/index.ts:592
    const w = spawnSync("which", [name], { encoding: "utf8" });
  • 执行外部命令固定命令
    plugin/src/index.ts:654
    const out = spawnSync("ps", ["-p", String(pid), "-o", "comm="], { encoding: "utf8" });
  • 读取本地文件
    plugin/src/index.ts:660
    try { return Number(readFileSync(join(RUN_DIR, name + ".pid"), "utf8").trim()); } catch { return 0; }
  • 读取本地文件
    plugin/src/index.ts:671
    const s = readFileSync(PROFILE_PATCH, "utf8");
  • 写入本地文件
    plugin/src/index.ts:734
    try { writeFileSync(SETTINGS_FILE, JSON.stringify(s, null, 2)); } catch { }
  • 删除本地文件
    plugin/src/index.ts:743
    rmSync(join(RUN_DIR, name + ".pid"));
  • 写入本地文件
    plugin/src/index.ts:756
    writeFileSync(caddyfile, renderCaddyfile());
  • 执行外部命令来自配置/变量
    plugin/src/index.ts:757
    caddyChild = spawn(findBinary(cfg, "caddy"), ["run", "--config", caddyfile], {
  • 写入本地文件
    plugin/src/index.ts:762
    writeFileSync(join(RUN_DIR, "caddy.pid"), String(caddyChild.pid));
  • 执行外部命令来自配置/变量
    plugin/src/index.ts:783
    cloudflaredChild = spawn(findBinary(cfg, "cloudflared"),
  • 删除本地文件
    plugin/src/index.ts:840
    for (const f of ["caddy.pid", "cloudflared.pid", "url"]) { try { rmSync(join(RUN_DIR, f)); } catch { } }
  • 删除本地文件
    plugin/src/index.ts:984
    for (const f of ["caddy.pid", "cloudflared.pid", "url"]) { try { rmSync(join(RUN_DIR, f)); } catch { } }
扫描于 2026/11/4(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库
涉及外部主机:open.feishu.cn

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 隧道远程访问
  • 密码门禁
  • 飞书通知

为 DeepSeek Harness(DSH)提供安全的远程访问:Cloudflare Tunnel + 密码门禁 + 飞书通知。macOS 优先,Linux 同样一等支持。

README

由 DeepSeek 最新模型翻译生成
dsh-remote-control 让你从任意地点安全访问部署在自己 Mac 或 Linux 服务器上的 DeepSeek Harness(DSH)—— Cloudflare 隧道 → 密码门 → DSH,入口地址或服务状态一有变化,飞书卡片通知立刻推到你手机。 浏览器 ──HTTPS──▶ Cloudflare 边缘(Quick Tunnel: https://<随机>.trycloudflare.com) │ 只有出站连接,不开任何入站端口 ▼ cloudflared ──▶ Caddy(密码门 + 会话 Cookie) │ http://127.0.0.1:3080 ▼ DSH web profile(只绑 loopback,零改动) 为什么做这个 - 不开任何入站端口——主机只通过隧道发起出站连接。 - DSH 前面有密码门——登录页 + 签名会话 Cookie(7 天有效),连续错 5 次锁定来源 IP。 DSH 本体零改动。 - 飞书通知是刚需,不是锦上添花——Quick Tunnel 每次启动都分配新的随机 URL,没有推送通道就等于失联。每次 start / URL 变化 / 故障 / 恢复都会推送卡片,并单独发一条可直接复制的密码纯文本消息。 - DSH 升级免疫——链路只与 127.0.0.1:3080 说 HTTP,不碰任何 DSH 内部 API。
展开完整文档(README 剩余 1 节)
dsh-remote-control

让你从任意地点安全访问部署在自己 Mac 或 Linux 服务器上的 DeepSeek Harness(DSH)—— Cloudflare 隧道 → 密码门 → DSH,入口地址或服务状态一有变化,飞书卡片通知立刻推到你手机。

浏览器 ──HTTPS──▶ Cloudflare 边缘(Quick Tunnel: https://<随机>.trycloudflare.com) │ 只有出站连接,不开任何入站端口 ▼ cloudflared ──▶ Caddy(密码门 + 会话 Cookie) │ http://127.0.0.1:3080 ▼ DSH web profile(只绑 loopback,零改动)

为什么做这个

- 不开任何入站端口——主机只通过隧道发起出站连接。
- DSH 前面有密码门——登录页 + 签名会话 Cookie(7 天有效),连续错 5 次锁定来源 IP。
DSH 本体零改动。
- 飞书通知是刚需,不是锦上添花——Quick Tunnel 每次启动都分配新的随机 URL,没有推送通道就等于失联。每次 start / URL 变化 / 故障 / 恢复都会推送卡片,并单独发一条可直接复制的密码纯文本消息。
- DSH 升级免疫——链路只与 127.0.0.1:3080 说 HTTP,不碰任何 DSH 内部 API。

快速开始

环境要求:macOS(x86_64 / arm64)或 Linux(x86_64 / arm64)、curl、python3。
Windows 不在官方支持范围——欢迎附实测证据提 PR。

git clone https://github.com/oh-summy/dsh-remote-control.git
cd dsh-remote-control
scripts/install.sh # 下载官方 cloudflared/caddy 二进制,生成密码

无需 git clone 直接安装

更推荐直接使用 GitHub Release(免 git):

一键安装(最新版)
curl -fsSL https://raw.githubusercontent.com/oh-summy/dsh-remote-control/main/scripts/install-remote.sh | bash

或指定版本
curl -fsSL https://raw.githubusercontent.com/oh-summy/dsh-remote-control/main/scripts/install-remote.sh | bash -s -- v0.3.0

该脚本会从 GitHub Releases 下载官方源码包,校验 SHA256 后运行 install.sh (它会自动下载对应平台/架构的 cloudflared 与 caddy)。注意:SHA256 属于完整性校验,防下载损坏,不构成真实性/防篡改证明(校验和与包同源)。全部版本见: <https://github.com/oh-summy/dsh-remote-control/releases>。

默认情况下,dsh-web start 会自动检测 DSH web 是否已运行,若未运行则自动拉起。
如需禁用此行为,在 ~/.remote-control/rc.env 中设置 RC_AUTOSTART_DSH=false。
(若自动启动失败,查看 dsh-web logs dshweb 或手动执行 dsh web。)

DSH web(≥0.1.5)在密码门之外还有自己的签名 cookie 认证。登录成功时 remote-control 会自动签发该 cookie,无需额外步骤。若看到 dsh web authentication required,说明那一刻凭据不可读(如 DSH 刚重启),重新登录一次即可。

然后编辑 ~/.remote-control/rc.env:

- 主通知通道(bot 私发):填 RC_FEISHU_OPEN_ID(你的 open id,ou_ 开头)。需要安装并配置 lark-cli(lark-cli config init 配置你的飞书应用),应用机器人需有发消息权限且能给你发私信。
- 兜底通道:填 RC_FEISHU_WEBHOOK(群自定义机器人 Webhook),无需 lark-cli。
两者都填时优先私发,失败才走 Webhook。

启动:

dsh-web start

start 会在终端打印 URL 和密码后返回命令行,同时推送卡片 + 密码到你的飞书私聊。打开 URL,输一次密码即可,Cookie 7 天内免登录。

自愈与进程守护

- 看门狗常驻自愈:caddy/auth 退出会被原地重拉(URL 不变);cloudflared 退出会自动重建隧道(Quick Tunnel 换新 URL,新卡片自动推到飞书),失败时按 30s→600s 退避重试,全部失败才推送人工介入告警,并进入冷却(不重复轰炸),dsh-web start 成功后自动解除。
- 开机自启 + 守护看门狗:dsh-web autostart 通过 launchd KeepAlive 守护看门狗本身——开机自动拉起全链路,看门狗被误杀也会被立即重拉。人工 dsh-web stop 期间守护自动待命,不会和你的操作打架。
- 升级说明:从 ≤ v0.2.x 升级且已开自启的机器,开机任务仍是旧版配置(不会自动变化),请执行一次 dsh-web install(或 dsh-web autostart)切换到常驻守护模式; dsh-web autostart off 会把常驻看门狗一并停掉。

命令

| 命令 | 用途 |
| dsh-web start | 启动全链路,终端打印 URL + 密码(飞书同步通知) |
| dsh-web stop | 停止全链路 |
| dsh-web restart | 重启(URL 会变,自动推新卡片) |
| dsh-web status | 组件状态 + 认证墙/上游健康度 |
| dsh-web logs [caddy\|cloudflared\|auth\|watchdog\|selfheal\|notify\|all] | 查看日志 |
| dsh-web password | 打印访问密码 |
| dsh-web url | 打印当前入口 URL |
| dsh-web install | 安装/修复(二进制、配置、凭据、命令链接) |
| dsh-web tunnel-setup | 引导创建 Named Tunnel(固定域名) |
| dsh-web rotate-password | 轮换访问密码(生成新密码并重启服务) |
| dsh-web autostart [off] | 安装/卸载 launchd 开机自启(macOS) |

配置——~/.remote-control/rc.env

| 变量 | 默认值 | 说明 |
| RC_UPSTREAM | 127.0.0.1:3080 | 要保护的本地服务(任何本地 HTTP 服务,不限 DSH) |
| RC_LISTEN | 127.0.0.1:4080 | Caddy 监听地址(只绑回环) |
| RC_FEISHU_OPEN_ID | — | 飞书私聊通知的 open id(主通道) |
| RC_FEISHU_WEBHOOK | — | 群自定义机器人 Webhook(兜底通道) |
| RC_NOTIFY_PASSWORD | full | full = 密码单独成条推送;mask = 只推后 4 位;其他值 = 不发送密码消息 |
| RC_NOTIFY_NOTE | — | 通知卡片顶部自定义说明(显示在访问地址之前);每次通知实时读取,改后无需重启 |
| RC_TUNNEL_NAME | — | Named Tunnel 名称(可选,用于固定域名) |
| RC_TUNNEL_HOSTNAME | — | Named Tunnel 域名(可选,如 dsh.example.com) |
| RC_TUNNEL_PROTOCOL | http2 | 隧道传输协议。本机开着代理 TUN(如 Clash Verge)时保持 http2——QUIC/UDP 长连接会随 TUN 路由抖动,公网侧表现为间歇性 502/530;纯净网络可改 quic |

运行时数据(密码、令牌、日志)都在 ~/.remote-control/,权限 600,永不进 git。

平台支持

| 平台 | 状态 |
| macOS x86_64 / arm64 | ✅ 开发与验收平台 |
| Linux x86_64 / arm64(Ubuntu/Debian 优先) | ✅ 同一安装器,systemd 单元规划中(M3) |
| Windows | ❌ 不官方支持;欢迎附实测证据提 PR |

安全说明

- DSH 始终只绑 127.0.0.1;唯一公网暴露面是密码门之后的 Cloudflare 边缘。
- 密码:128 位随机生成,本地保存(权限 600);连续失败 5 次锁定来源 IP 5 分钟(HTTP 429)。
- 会话 Cookie 为 HttpOnly + SameSite=Lax,7 天有效。轮换方式:重新生成密码(scripts/gen-password.sh)和/或修改 ~/.remote-control/session.secret,然后 dsh-web restart。
- 严禁提交 rc.env、password、session.secret 和渲染后的 Caddyfile——.gitignore 已覆盖,CI 与评审双重把关。

Named Tunnel(固定域名)

默认情况下,Quick Tunnel 每次启动分配随机 URL。如需固定域名:

1. 登录 Cloudflare cloudflared tunnel login

2. 创建隧道 cloudflared tunnel create my-dsh-tunnel

3. 配置 DNS 路由 cloudflared tunnel route dns my-dsh-tunnel dsh.example.com

4. 编辑 ~/.remote-control/rc.env
RC_TUNNEL_NAME="my-dsh-tunnel"
RC_TUNNEL_HOSTNAME="dsh.example.com"

5. 重启 dsh-web restart

或运行 dsh-web tunnel-setup 查看引导步骤。

架构设计

系统架构、设计决策、组件交互见 docs/architecture.md。

DSH 插件——@oh-summy/dsh-remote

本仓库同时把同一能力做成了 DSH 原生插件(plugin/):在 DSH 自己的 UI 里启用——Settings → Built-in plugins → 远程访问——不开终端就能拿到 Cloudflare 临时链接 + 密码门。设计与实现事实:docs/dsh-plugin-design.md。

- 安装(装进 DSH profile):dsh plugin --profile web add @oh-summy/dsh-remote(tag v0.1.0 发布后可从市场安装)。
- 插件取代脚本网关的 watchdog/auth 层:跑在 DSH 宿主进程内,自行管理 cloudflared + caddy,登录页由自己的 listener 承载。二选一启用,不要同时开(插件发现 4080 被脚本网关占用会 fail-loud:先 dsh-web stop)。
- 通知凭据绝不写进配置文件——走 DSH 的凭据缝(~/.dsh/.credentials.yaml),页面只显示掩码。

路线图

各阶段进度与后续计划见 docs/roadmap.md。

参与贡献

见 CONTRIBUTING.md · English。简言之:CI 必须通过(shellcheck + 语法检查)、脚本保持 bash 3.2 / POSIX 兼容、平台相关改动必须附真实测试证据。

许可证

MIT © 2026 Summy Wu (oh-summy)
预览分享卡片长什么样 ↓oh-summy/dsh-remote-control
分享 · DeepSeek Harness Hub
oh-summy/dsh-remote-control

通过隧道与密码门,从任意地点安全访问本机服务

这是你的仓库?认领条目

回到顶部