dsh-mobile 0.4.7 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,16 @@
1
1
  # Third-party notices
2
2
 
3
- DSH Mobile includes a small Windows helper built from the source in `native/funnel-host`. The helper uses [Tailscale tsnet](https://pkg.go.dev/tailscale.com/tsnet) `v1.102.3`, distributed under the BSD 3-Clause license. Its exact statically linked Go module versions and complete license and notice texts are generated from the bundled executable into `FUNNEL_THIRD_PARTY_LICENSES.txt`, which is included in every npm package.
3
+ DSH Mobile includes platform-specific Windows and Linux Funnel helpers built from the source in `native/funnel-host`. They use [Tailscale tsnet](https://pkg.go.dev/tailscale.com/tsnet) `v1.102.3`, distributed under the BSD 3-Clause license. Their exact statically linked Go module versions and complete license and notice texts are generated from the bundled executables into `FUNNEL_THIRD_PARTY_LICENSES.txt`, which is included in every npm package.
4
4
 
5
5
  The optional cpolar component is not included in the npm package or Android App. When a user explicitly chooses cpolar installation, DSH Mobile downloads the pinned official archive shown in the UI, verifies its size and SHA-256 digest, and stores it only under the user's DSH Mobile data directory. cpolar remains subject to its [terms of service](https://www.cpolar.com/tos).
6
6
 
7
7
  The optional [FRP](https://github.com/fatedier/frp) client is not included in the npm package or Android App. When a user explicitly chooses self-hosted FRP installation, DSH Mobile downloads the pinned official `frpc` 0.70.1 archive, verifies its origin, exact size, SHA-256 digest, archive paths, and executable version, then stores only `frpc` under the user's DSH Mobile data directory. FRP is distributed under the Apache License 2.0.
8
8
 
9
- The optional [cloudflared](https://github.com/cloudflare/cloudflared) client is not included in the npm package or Android App. When a user explicitly chooses cloudflared installation, DSH Mobile downloads the pinned official `cloudflared-windows-amd64.exe` release asset (version recorded in `src/cloudflared-component.ts`), verifies its exact size and SHA-256 digest, and stores it only under the user's DSH Mobile data directory. The client is started with automatic updates disabled and no account credential is requested or stored. cloudflared is distributed under the Apache License 2.0; use of Cloudflare's quick tunnels remains subject to Cloudflare's [website terms](https://www.cloudflare.com/website-terms/).
9
+ The optional [cloudflared](https://github.com/cloudflare/cloudflared) client is not included in the npm package or Android App. When a user explicitly chooses cloudflared installation, DSH Mobile downloads the pinned official release asset for the supported host platform (version recorded in `src/cloudflared-component.ts`), verifies its exact size and SHA-256 digest, and stores it only under the user's DSH Mobile data directory. The client is started with automatic updates disabled. Quick tunnels do not require account credentials; named tunnels use an operator-supplied connector token stored in the plugin's private directory. cloudflared is distributed under the Apache License 2.0; use of Cloudflare's quick tunnels remains subject to Cloudflare's [website terms](https://www.cloudflare.com/website-terms/).
10
10
 
11
- The npm package declares direct runtime dependencies on [Schemastery](https://github.com/shigma/schemastery) `^3.18.1`, [bonjour-service](https://github.com/onlxltd/bonjour-service) `^1.4.4`, [qrcode](https://github.com/soldair/node-qrcode) `^1.5.4`, and [selfsigned](https://github.com/jfromaniello/selfsigned) `^5.5.0`. These packages are distributed under the MIT License; the release checkout's exact transitive versions appear in the attached CycloneDX npm SBOM.
11
+ The npm package declares direct runtime dependencies on [Schemastery](https://github.com/shigma/schemastery) `^3.18.1`, [bonjour-service](https://github.com/onlxltd/bonjour-service) `1.4.4`, [qrcode](https://github.com/soldair/node-qrcode) `^1.5.4`, and [selfsigned](https://github.com/jfromaniello/selfsigned) `^5.5.0`. These packages are distributed under the MIT License; the release checkout's exact transitive versions appear in the attached CycloneDX npm SBOM.
12
12
 
13
- The Android App runtime contains [Kotlin standard library](https://github.com/JetBrains/kotlin) `2.1.0`, [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) `1.6.4`, [JetBrains annotations](https://github.com/JetBrains/java-annotations) `13.0`, [AndroidX Core](https://developer.android.com/jetpack/androidx/releases/core) `1.15.0`, [AndroidX WebKit](https://developer.android.com/jetpack/androidx/releases/webkit) `1.12.1`, their AndroidX transitive components, [Guava listenablefuture](https://github.com/google/guava) `1.0`, and [ZXing Core](https://github.com/zxing/zxing) `3.5.4`. These runtime libraries are distributed under the Apache License 2.0; the exact resolved tree is attached to each release as `dsh-mobile-android-v<version>-dependencies.txt`.
13
+ The Android App runtime contains [Kotlin standard library](https://github.com/JetBrains/kotlin) `2.1.0`, [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) `1.6.4`, [JetBrains annotations](https://github.com/JetBrains/java-annotations) `13.0`, [AndroidX Core](https://developer.android.com/jetpack/androidx/releases/core) `1.15.0`, [AndroidX WebKit](https://developer.android.com/jetpack/androidx/releases/webkit) `1.17.1`, their AndroidX transitive components, [Guava listenablefuture](https://github.com/google/guava) `1.0`, and [ZXing Core](https://github.com/zxing/zxing) `3.5.4`. These runtime libraries are distributed under the Apache License 2.0; the exact resolved tree is attached to each release as `dsh-mobile-android-v<version>-dependencies.txt`.
14
14
 
15
15
  ## core-js browser compatibility bundle
16
16
 
@@ -1,5 +1,7 @@
1
1
  # Attach to an existing frps
2
2
 
3
+ [中文指南](ATTACH_EXISTING_FRPS.md)
4
+
3
5
  > **Requires plugin 0.4.6**; the self-signed entry also requires the 0.4.6 Android app. Android apps 0.3.3–0.4.5 can use the public-CA entry but not the self-signed entry.
4
6
 
5
7
  Use this path when you already run frps on a public VPS. The plugin does not install, edit, or restart that frps and does not automatically change your Caddyfile; public-CA mode requires **you** to add a Caddy snippet and import. Inspect the server's listeners before choosing an entry mode. The panel's **Copy attachment plan** action only produces a masked local `frpc.toml` preview and VPS instructions; it neither connects to the VPS nor writes configuration. To copy a token-bearing local config, re-enter the token and explicitly click its copy button; a saved token is never returned to the page.
@@ -1,5 +1,7 @@
1
1
  # 接入你既有的 frps(插件不自动改动服务器)
2
2
 
3
+ [English guide](ATTACH_EXISTING_FRPS.en.md)
4
+
3
5
  > **需要 0.4.6 插件**;自签档还必须使用 0.4.6 Android App。Android App 0.3.3–0.4.5 可使用公开证书档,但不支持自签档。
4
6
 
5
7
  本文面向**已经在一台公网 VPS 上跑着 frps**的用户。插件不会安装、修改或重启你的 frps,也不会自动改动 Caddyfile;若选择公开 CA 档,你需要自行新增 Caddy 片段和 `import`。本机侧不改动 DSH 自身配置。接入前须核对既有 frps 的监听;若它不满足所选入口档的要求,插件不会代你修改。
@@ -96,3 +98,5 @@ curl -k -sS -o /dev/null -w '%{http_code}\n' https://YOUR_PUBLIC_IPV4:33080/mobi
96
98
 
97
99
  - **`origin` 自有反代通道**(默认 3444)是另一条独立路径,TLS 由**你自己的外部反代**终止,与本档互不影响。
98
100
  - **deploy 模式**(由插件安装 frps + Caddy)保持不变,仍需要 SSH;attach 模式**零 SSH**。
101
+
102
+ 本机的「彻底移除 FRP」只清理插件管理的 frpc、私有配置和自签入口材料,不会删除或重启 VPS 上你已有的 frps、Caddy、证书或防火墙规则。托管部署及其独立的服务器清理步骤见[自建 FRP 使用指南](SELF_HOSTED_FRP.md)。
@@ -1,5 +1,7 @@
1
1
  # Cloudflare named tunnel (a stable public hostname)
2
2
 
3
+ [中文指南](CLOUDFLARE_TUNNEL.md)
4
+
3
5
  The built-in cloudflared provider runs in one of two modes, chosen in the panel under **Mobile access → Remote → cloudflared → Tunnel type**:
4
6
 
5
7
  | | Quick tunnel (default) | Named tunnel |
@@ -52,11 +54,11 @@ Moving to a fixed hostname means **an already paired phone must pair again**: a
52
54
  >
53
55
  > Scanning is optional: the full link (`https://your-domain/mobile-access/pair#instance=…&token=…`) can be copied to the phone and pasted, because the app accepts a complete link in its input field.
54
56
 
55
- The old remote entry in the device list will show **Address may have changed** or unreachable; delete it once the new pairing succeeds.
57
+ The old address may show **Address may have changed** or temporarily unreachable before re-pairing. After pairing the same computer again, the app updates its existing remote-device record by device identity and keeps the custom name; there is no old entry to delete.
56
58
 
57
59
  ## Security boundary
58
60
 
59
- - The token is written only into the DSH Mobile private directory (`~/.dsh/mobile-access/remote/cloudflared/tunnel.json`, mode 0600) and is passed to `cloudflared` **only** through the `TUNNEL_TOKEN` environment variable, never on the command line, which any local process can read.
61
+ - The token is written only into the DSH Mobile private directory (by default `$DSH_HOME/mobile-access/remote/cloudflared/tunnel.json`; Unix mode `0600`, restricted ACL on Windows) and is passed to `cloudflared` **only** through the `TUNNEL_TOKEN` environment variable, never on the command line.
60
62
  - The token is never returned to a browser or a phone. Panel status carries only whether it is configured, plus the hostname and port.
61
63
  - Behind the tunnel sits DSH Mobile's own authenticated gateway: the public hostname exposes that gateway, and DSH still requires paired-device credentials.
62
64
  - The plugin adds no system service, startup item, registry entry or PATH entry. Disabling the channel ends the process.
@@ -90,24 +92,17 @@ The old remote entry in the device list will show **Address may have changed** o
90
92
 
91
93
  ## Troubleshooting
92
94
 
93
- - **Stuck on "connecting"**: a named tunnel prints no banner, so it only becomes ready once the connector registers. Read the cloudflared output in the DSH log; the `CONNECTIVITY PRE-CHECKS` table says whether DNS, UDP/QUIC or TCP is the problem.
95
+ - **Stuck on "connecting"**: the named tunnel becomes ready only after the connector registers with Cloudflare. Check cloudflared output in the DSH log and test DNS, UDP/QUIC and TCP reachability from the computer to a Cloudflare edge.
94
96
  - **Public access returns 1033**: Cloudflare believes no connector is healthy for that hostname. Check the tunnel shows Healthy in Zero Trust, and that its ingress port matches the panel.
95
97
  - **`cloudflared` reports `Unauthorized`, or the tunnel id does not exist**: the token belongs to a different tunnel, for example one that was deleted and recreated. Copy the token again.
96
- - **With a TUN or transparent proxy running (Clash, Mihomo, Clash Verge), the phone sticks on "Loading plugins" and retries forever.** This is a real failure that was measured, and it is easy to misread as a pairing or plugin problem:
97
- - `cloudflared`'s connection to `region*.v2.argotunnel.com` has no dedicated rule, so it falls through to the catch-all `Match`/`MATCH` rule and is sent into a proxy node. The core's own API shows it plainly:
98
- ```
99
- cloudflared.exe -> region2.v2.argotunnel.com
100
- rule=Match chains=["<some airport node>","漏网之鱼"] up/down = 103 MB / 2.1 MB
101
- ```
102
- - Downstream throughput then collapses to **8–100 KB/s**. The phone's DSH boot pulls a **4.5 MB** (compressed) boot bundle in one shot, the loader gives up, and the app shows "load, fail, retry".
103
- - The same file took **0.2 s** on the LAN gateway, and **9.9 s / 454 KB/s** through the tunnel once routing was fixed — two orders of magnitude apart.
104
- - Fix: route cloudflared and its edge domains directly. In Clash Verge's **global merge profile** (`profiles/Merge.yaml`, which subscription updates do not overwrite):
105
- ```yaml
106
- prepend-rules:
107
- - PROCESS-NAME,cloudflared.exe,DIRECT
108
- - DOMAIN-SUFFIX,argotunnel.com,DIRECT
109
- - DOMAIN-SUFFIX,trycloudflare.com,DIRECT
110
- ```
111
- Then make cloudflared **reconnect**: hot-reloading the core does not migrate long-lived connections (use the panel's reconnect action, or toggle the provider off and on).
112
- - To confirm it is this and not the phone: fetch the boot bundle from the computer with the same session and watch the rate. If the computer is just as slow, the phone and pairing are innocent.
98
+ - **The phone stalls on "Loading plugins" or the remote page is slow while a TUN or transparent proxy is active**: check whether a catch-all rule sends `cloudflared` connections to `*.argotunnel.com` through a proxy node. This routing has caused slow boot-resource transfers before; it does not by itself indicate a pairing failure. This Clash-rule example is for Windows; on Linux, adapt the process name and syntax to your proxy client, and put direct-route rules before catch-all rules:
99
+
100
+ ```yaml
101
+ prepend-rules:
102
+ - PROCESS-NAME,cloudflared.exe,DIRECT
103
+ - DOMAIN-SUFFIX,argotunnel.com,DIRECT
104
+ - DOMAIN-SUFFIX,trycloudflare.com,DIRECT
105
+ ```
106
+
107
+ Then make cloudflared **reconnect** so existing connections take the new route (use the panel's reconnect action, or toggle the provider off and on). Compare the same resource through the LAN and remote entries. If the remote entry is also slow on the computer, inspect the computer-to-Cloudflare route first; if only the phone is slow, inspect its network.
113
108
  - **The domain still resolves to the old address**: after the nameserver change Cloudflare must move the zone from Pending to Active, and records in a pending zone are not served publicly.
@@ -1,5 +1,7 @@
1
1
  # Cloudflare 命名隧道(固定公网域名)
2
2
 
3
+ [English guide](CLOUDFLARE_TUNNEL.en.md)
4
+
3
5
  内置的 cloudflared 通道有两种模式,在面板 **移动访问 → 远程 → cloudflared → 隧道类型** 中切换:
4
6
 
5
7
  | | 快速隧道(默认) | 命名隧道 |
@@ -52,11 +54,11 @@
52
54
  >
53
55
  > 不想扫码时,完整链接(`https://你的域名/mobile-access/pair#instance=…&token=…`)可以整条复制到手机上粘贴,App 的输入框接受完整链接。
54
56
 
55
- 设备列表里原来那条远程记录会显示「地址可能已变化 / Address may have changed」或不可达,重新配对成功后删掉即可。
57
+ 旧地址在重新配对前可能显示「地址可能已变化」或暂不可达。重新配对同一台电脑后,App 会按设备标识更新原远程记录,保留自定义名称;无需删除它。
56
58
 
57
59
  ## 安全边界
58
60
 
59
- - 令牌只写入 DSH Mobile 私有目录(`~/.dsh/mobile-access/remote/cloudflared/tunnel.json`,权限 0600),并且**只**通过子进程环境变量 `TUNNEL_TOKEN` 传给 `cloudflared`,不出现在命令行里(本机任何进程都能读到命令行)。
61
+ - 令牌只写入 DSH Mobile 私有目录(默认 `$DSH_HOME/mobile-access/remote/cloudflared/tunnel.json`;Unix 权限 `0600`,Windows 使用受限 ACL),并且**只**通过子进程环境变量 `TUNNEL_TOKEN` 传给 `cloudflared`,不出现在命令行里。
60
62
  - 令牌从不回传给浏览器或手机端;面板状态里只有「是否已配置」、域名和端口。
61
63
  - 隧道背后是 DSH Mobile 自己的认证网关:公网主机名只暴露该网关,DSH 本体仍然需要配对设备凭据。
62
64
  - 插件不会创建系统服务、开机启动项、注册表项或 PATH 项;关闭通道即结束进程。
@@ -90,24 +92,17 @@
90
92
 
91
93
  ## 排错
92
94
 
93
- - **连接一直停在「正在连接」**:命名隧道没有横幅,只有 connector 真正注册后才算就绪。查看 DSH 日志里 cloudflared 的输出;预检表(`CONNECTIVITY PRE-CHECKS`)会指出是 DNS、UDP/QUIC 还是 TCP 不通。
95
+ - **连接一直停在「正在连接」**:命名隧道只有在 connector 向 Cloudflare 注册后才显示就绪。检查 DSH 日志中的 cloudflared 输出,以及本机到 Cloudflare 边缘的 DNS、UDP/QUIC 和 TCP 连通性。
94
96
  - **公网访问返回 1033**:Cloudflare 认为该主机名没有健康的 connector。确认隧道在 Zero Trust 里显示 Healthy,且 ingress 指向的端口与面板一致。
95
97
  - **`cloudflared` 报 `Unauthorized` 或隧道 ID 不存在**:令牌与控制台里的隧道不匹配(例如隧道被删除后重建)。重新复制令牌。
96
- - **本机开着 TUN/透明代理(Clash、Mihomo、Clash Verge 等):手机端会卡在「正在加载插件」并反复重试。** 这是实测到过的一类真实故障,症状很容易被误判成配对或插件问题:
97
- - `cloudflared` 到 `region*.v2.argotunnel.com` 的连接没有任何专属规则,于是落到兜底的 `Match`/`MATCH` 规则,被送进代理节点。用内核 API 看得很清楚:
98
- ```
99
- cloudflared.exe -> region2.v2.argotunnel.com
100
- rule=Match chains=["<某个机场节点>","漏网之鱼"] up/down = 103 MB / 2.1 MB
101
- ```
102
- - 结果下行被压到 **8–100 KB/s**。而手机端 DSH 启动要一次拉 **4.5 MB**(压缩后)的 boot bundle,加载器等不到就报 `bundle script failed to load`,App 表现为「加载 → 失败 → 重试」。
103
- - 同一份文件在局域网网关上是 **0.2 秒**,加上直连规则后走隧道是 **9.9 秒 / 454 KB/s** —— 差了两个数量级。
104
- - 修法:让 cloudflared 与其边缘域名走直连。Clash Verge 的**全局扩展配置**(`profiles/Merge.yaml`,订阅更新不会覆盖):
105
- ```yaml
106
- prepend-rules:
107
- - PROCESS-NAME,cloudflared.exe,DIRECT
108
- - DOMAIN-SUFFIX,argotunnel.com,DIRECT
109
- - DOMAIN-SUFFIX,trycloudflare.com,DIRECT
110
- ```
111
- 改完要让 cloudflared **重连**才会换路由:内核热重载不会迁移已建立的长连接(面板里点重连,或开关一次提供方)。
112
- - 判断方法:如果手机端一直卡在加载插件,先在**本机**用同一份会话拉一次 boot bundle 看速率。若本机也很慢,就不是手机或配对的问题。
98
+ - **手机卡在「正在加载插件」或远程页面明显慢,而本机开着 TUN/透明代理**:先检查 `cloudflared` 到 `*.argotunnel.com` 的连接是否被兜底规则送进代理节点。曾有这种路由导致启动资源传输很慢;它不等于配对失败。以下是 Windows 上 Clash 客户端的规则示例;Linux 的进程名与具体规则语法应按所用客户端调整,并让直连规则排在兜底规则前:
99
+
100
+ ```yaml
101
+ prepend-rules:
102
+ - PROCESS-NAME,cloudflared.exe,DIRECT
103
+ - DOMAIN-SUFFIX,argotunnel.com,DIRECT
104
+ - DOMAIN-SUFFIX,trycloudflare.com,DIRECT
105
+ ```
106
+
107
+ 改完后让 cloudflared **重连**,使已建立的连接使用新路由(面板里点重连,或开关一次提供方)。对比同一资源经局域网与远程入口的加载速度;若远程入口在电脑上也慢,优先检查电脑到 Cloudflare 的路径,若只有手机慢,再检查手机网络。
113
108
  - **域名解析还是旧地址**:改完 NS 后 Cloudflare 需要把 zone 从 Pending 变为 Active;A/CNAME 在 zone 激活前不会对外生效。
@@ -1,6 +1,6 @@
1
1
  # DeepSeek Harness 0.1.5 局域网验证
2
2
 
3
- 本页记录 DSH Mobile 0.3.15 对 DeepSeek Harness 0.1.5 的局域网兼容性证据,以及该次实测没有覆盖的远程路径。
3
+ 本页是 DSH Mobile 0.3.15 对 DeepSeek Harness 0.1.5 的历史局域网验证记录,不表示当前版本或远程通道已通过同一测试。当前支持组合见[项目兼容性表](../README.md#兼容性)。
4
4
 
5
5
  ## 验证环境
6
6
 
package/docs/README.md CHANGED
@@ -19,10 +19,10 @@
19
19
 
20
20
  | 文档 | 内容 |
21
21
  | --- | --- |
22
- | [DSH 0.1.5 局域网验证记录](DSH_0.1.5_LAN.md) | DSH Mobile 0.3.15 对 DeepSeek Harness 0.1.5 的局域网兼容验证 |
22
+ | [DSH 0.1.5 局域网验证记录](DSH_0.1.5_LAN.md) | DSH Mobile 0.3.15 的历史局域网实测;当前版本组合请看[兼容性表](../README.md#兼容性) |
23
23
 
24
24
  ## 面向维护者 / Maintainer notes
25
25
 
26
26
  维护者文档面向改代码的人,**不随 npm 包发布**,只在仓库中阅读:
27
27
 
28
- - `docs/HANDOFF_SELF_HOSTED_FRP.md` —— 自建 FRP 的代码地图、错误码、安全边界与真机验证记录。
28
+ - [自建 FRP 维护记录](HANDOFF_SELF_HOSTED_FRP.md) —— 0.4.6 开发时的代码地图、安全检查点与历史真机验证;当前使用步骤以本页上方的用户指南为准。
@@ -20,7 +20,7 @@ Android app
20
20
  - **Domain mode**: use your own public domain; Caddy obtains and renews the certificate automatically.
21
21
  - **Public IPv4 mode**: use the VPS public IPv4 address directly. The plugin uses Certbot to request a roughly six-day Let's Encrypt IP certificate and installs a daily renewal timer. Documentation ranges such as `203.0.113.10`, private addresses, and other reserved addresses are rejected; enter a real routable public IP.
22
22
 
23
- The publicly trusted entry in this guide requires Android app 0.3.3 or later for custom remote origins. Self-signed passthrough requires the 0.4.6 app with remote CA pinning; older apps cannot use that entry and continue to work with LAN, cpolar, and Tailscale.
23
+ The publicly trusted entry in this guide requires Android app 0.3.3 or later for custom remote origins. The separate self-signed TCP passthrough in the [existing-frps attachment guide](ATTACH_EXISTING_FRPS.en.md) is attach-only and requires the 0.4.6 or later app with remote CA pinning; older apps cannot use that entry and continue to work with LAN, cpolar, and Tailscale.
24
24
 
25
25
  ## Manual deployment vs automatic deployment
26
26
 
@@ -53,12 +53,14 @@ Public IPv4 mode also removes the corresponding Let's Encrypt IP certificate. Do
53
53
  On the VPS:
54
54
 
55
55
  ```bash
56
- sudo systemctl status dsh-mobile-frps.service caddy dsh-mobile-cert-renew.timer
56
+ sudo systemctl status dsh-mobile-frps.service caddy
57
57
  sudo journalctl -u dsh-mobile-frps.service -u caddy -n 200 --no-pager
58
58
  sudo ss -lntp
59
- curl -vk https://PUBLIC_HOST/
59
+ curl -v https://PUBLIC_HOST/mobile-access/discovery
60
60
  ```
61
61
 
62
+ Only public IPv4 mode installs `dsh-mobile-cert-renew.timer`; in that mode, also run `sudo systemctl status dsh-mobile-cert-renew.timer`. Replace `PUBLIC_HOST` with your actual domain or public IPv4 address. Do not add `-k`: verify the public certificate as well as the response. Check the same address from an independent external network and confirm discovery reports this computer's installation identifier; success on the VPS alone does not prove the phone's network can reach it.
63
+
62
64
  On the computer, start with the plugin log at `$DSH_HOME/mobile-access/logs/dsh-mobile.log` (JSONL, 5 MB rotation, tokens and keys redacted) and the panel diagnostic report. Windows antivirus software can quarantine frpc; if it does, create the smallest possible exception for the verified component directory only.
63
65
 
64
66
  ## Limits
@@ -69,11 +71,6 @@ On the computer, start with the plugin log at `$DSH_HOME/mobile-access/logs/dsh-
69
71
  - VPS SSH targets currently cannot use IPv6.
70
72
  - The frps plaintext vhost must bind to `127.0.0.1`. The plugin rejects a publicly reachable plaintext port and reports readiness only after public discovery identifies the current computer.
71
73
 
72
- ## Manual end-to-end checklist (before release)
74
+ ## Acceptance check
73
75
 
74
- - [x] Ubuntu IP mode: one-click redeploy on a VPS → public IPv4 ready → App discovery returned this computer (2026-09-03, Tencent Cloud).
75
- - [ ] Ubuntu domain mode: fresh VPS deployment → public domain ready → App pairing → send and receive messages.
76
- - [x] Existing Caddy coexistence: deploy into a Caddyfile containing an existing site and import line; verify user content is byte-for-byte preserved, the import occurs exactly once, and validation passes (2026-09-03, Tencent Cloud; concurrent writes use `flock`).
77
- - [x] Host-key change abort: an unconfirmed key set stops deployment/cleanup with `vps_host_key_mismatch` before network authentication (unit-test coverage plus full device fingerprint review).
78
- - [x] One-click cleanup: after deployment, services, files, timers, marked firewall rules, the owned system user, and the LE certificate were removed while the user's Caddy installation remained (2026-09-03, Tencent Cloud).
79
- - [x] Uninstall-script review: only DSH Mobile-owned paths and rules are touched (unit assertions plus device review).
76
+ After deployment, check the certificate, public discovery endpoint, app pairing, and a live conversation on your own VPS and phone network. The repository's historical tests are recorded in the [self-hosted FRP handoff](HANDOFF_SELF_HOSTED_FRP.md); they cannot replace your own acceptance test.
@@ -24,7 +24,7 @@
24
24
  - **域名模式**:公开地址是自己的域名,Caddy 自动申请并续期证书。
25
25
  - **公网 IPv4 模式**:公开地址直接是 VPS 公网 IPv4(例如你自己的 VPS 地址),插件用 Certbot 申请约 6 天有效的 Let's Encrypt IP 证书,并安装每日自动续期定时器。注意:文档示例地址(如 `203.0.113.10`)和内网、保留地址会被拒绝,必须填写真实可路由的公网 IP。
26
26
 
27
- 本页的公开证书入口需要 Android App 0.3.3 或更高版本(远程自定义入口)。自签穿透档需要 0.4.6 Android App 固定远程 CA;旧版 App 不支持该档,仍可使用局域网、cpolar 和 Tailscale。
27
+ 本页的公开证书入口需要 Android App 0.3.3 或更高版本(远程自定义入口)。另见[接入既有 frps](ATTACH_EXISTING_FRPS.md)中的自签 TCP 穿透档:它仅适用于接入模式,需要 0.4.6 或更新的 Android App 固定远程 CA;旧版 App 不支持该档,仍可使用局域网、cpolar 和 Tailscale。
28
28
 
29
29
  ## 手动部署 vs 自动部署
30
30
 
@@ -57,12 +57,14 @@ SSH 用户、端口和私钥路径只保存在当前浏览器的 `localStorage`
57
57
  VPS 上:
58
58
 
59
59
  ```bash
60
- sudo systemctl status dsh-mobile-frps.service caddy dsh-mobile-cert-renew.timer
60
+ sudo systemctl status dsh-mobile-frps.service caddy
61
61
  sudo journalctl -u dsh-mobile-frps.service -u caddy -n 200 --no-pager
62
62
  sudo ss -lntp
63
- curl -vk https://PUBLIC_HOST/
63
+ curl -v https://PUBLIC_HOST/mobile-access/discovery
64
64
  ```
65
65
 
66
+ 只有公网 IPv4 模式会安装 `dsh-mobile-cert-renew.timer`,该模式另查 `sudo systemctl status dsh-mobile-cert-renew.timer`。将 `PUBLIC_HOST` 换成实际域名或公网 IPv4;不加 `-k`,以便同时验证公开证书。还应从独立外部网络检查同一地址,并确认 discovery 返回当前电脑的安装标识;只在 VPS 本机成功不代表手机网络可达。
67
+
66
68
  本机优先看插件日志(`$DSH_HOME/mobile-access/logs/dsh-mobile.log`,JSONL,超 5 MB 轮转,自动脱敏 Token 与密钥)与面板诊断报告。Windows 杀毒软件可能隔离 frpc;如确有拦截,只为已校验的组件目录设置最小范围例外。
67
69
 
68
70
  ## 限制
@@ -73,11 +75,6 @@ curl -vk https://PUBLIC_HOST/
73
75
  - VPS 的 SSH 目前不支持 IPv6 地址。
74
76
  - frps 明文 vhost 必须只监听 `127.0.0.1`;插件会拒绝公网可达的明文端口,并在公开发现接口确认是当前电脑后才显示“已就绪”。
75
77
 
76
- ## 手动端到端验证清单(发布前)
78
+ ## 上线前验收
77
79
 
78
- - [x] Ubuntu IP 模式:已部署 VPS 上一键重部署 → 公网 IP 就绪 → App 级 discovery 返回当前电脑(2026-09-03,腾讯云实测)。
79
- - [ ] Ubuntu 域名模式:全新 VPS 一键部署 → 公网域名就绪 → App 远程配对 → 收发消息。
80
- - [x] 既有 Caddy 共存:在已有自有站点 + import 行的 Caddyfile 上部署,确认自有内容逐字节保留、import 恰好一行、validate 通过(2026-09-03,腾讯云实测;并发写有 flock 互斥)。
81
- - [x] 指纹变更中止:未确认密钥集合部署/清理直接 `vps_host_key_mismatch` 中止且零网络碰触(单元测试锁定;真机指纹全量核对通过)。
82
- - [x] 一键清理:部署后执行一键清理,服务、文件、定时器、标记防火墙规则、系统用户、LE 证书均已移除,自有 Caddy 本体保留(2026-09-03,腾讯云实测)。
83
- - [x] 卸载脚本审阅:仅触碰 DSH Mobile 拥有的路径与规则(单元测试断言 + 真机复核)。
80
+ 部署后,请在你的实际 VPS 与手机网络上检查证书、外网发现接口、App 配对和实时对话;本仓库的历史实测记录见[自建 FRP 交接记录](HANDOFF_SELF_HOSTED_FRP.md),不能替代你自己的验收。
@@ -13,7 +13,7 @@ This provider appears under **Mobile Access → Remote → Self-hosted connectio
13
13
  - Separate LAN proxy: listen on the DSH computer's private IPv4, e.g. `192.168.50.10:3444`, and allow the proxy's actual direct source, e.g. `192.168.50.1/32`.
14
14
  - Only explicit loopback/RFC1918 IPv4 binds are supported. Wildcard, public and IPv6 binds are rejected. The port must be 1024–65535 and may not be 3443 (the LAN gateway) or 3080 (DSH's own WebServer); note that 3444 is also the cloudflared named tunnel's default forward port. Source CIDRs must be canonical private/loopback networks, at most 16; prefer a single-host /32. Forwarded headers do not determine source authorization.
15
15
 
16
- Select **Save and start backend**, then point the proxy at the displayed HTTP backend. **Never expose/port-forward that HTTP listener publicly**, and never bypass it by proxying to DSH 8080 (or its configured WebServer port) or the LAN 3443 gateway. HTTP between separate devices is suitable only for a trusted private network. Pairing, authentication, normalized-exact Host/Origin enforcement, CSRF, Secure cookies and WebSocket path policy remain active. Do not open the plain HTTP backend in a browser to verify it: cookies are marked `Secure`, so a browser discards them over `http://` and login or CSRF will fail with no visible reason.
16
+ Select **Save and start backend**, then point the proxy at the displayed HTTP backend. **Never expose/port-forward that HTTP listener publicly**, and never bypass it by proxying to DSH's WebServer (default port 3080) or the LAN 3443 gateway. HTTP between separate devices is suitable only for a trusted private network. Pairing, authentication, normalized-exact Host/Origin enforcement, CSRF, Secure cookies and WebSocket path policy remain active. Do not open the plain HTTP backend in a browser to verify it: it only accepts requests proxied from the configured public HTTPS origin; direct access has the wrong Host, and its cookie/CSRF flow may fail.
17
17
 
18
18
  ## Proxy contract
19
19
 
@@ -15,7 +15,7 @@
15
15
  ```
16
16
 
17
17
  - **只有第一段允许暴露公网。HTTP 后端不能做公网端口映射。** HTTP 段仅适用于可信私网;局域网其他设备上的代理也会接触明文流量。
18
- - 后端不是裸 DSH:仍执行设备配对、认证、归一化后精确匹配的 Host/Origin 校验、CSRF、Secure Cookie 和 WebSocket 路径策略。没有配对的访问不能直接进入 DSH。**不要用浏览器直接打开这个明文 HTTP 后端做验证**:Cookie 带 `Secure`,浏览器在 `http://` 下会丢弃它们,登录或 CSRF 会无提示失败。
18
+ - 后端不是裸 DSH:仍执行设备配对、认证、归一化后精确匹配的 Host/Origin 校验、CSRF、Secure Cookie 和 WebSocket 路径策略。没有配对的访问不能直接进入 DSH。**不要用浏览器直接打开这个明文 HTTP 后端做验证**:它只支持由指定 HTTPS 公网地址代理的请求;直接打开时 Host 不匹配,Cookie 与 CSRF 流程也可能失效。
19
19
  - 不要把公网反代目标改成 DSH 的 WebServer 端口(默认 3080),也不要反代现有 LAN HTTPS 3443。新后端默认 3444,**明确拒绝 3443 和 3080**,并拒绝 1024 以下需要特权的端口。注意 3444 同时是 cloudflared 命名隧道的默认转发端口:同一时刻只有一个远程提供方能运行,但切换到本提供方时请确认该端口已释放。DSH 与 LAN 的原有设置不变。
20
20
  - 公网 TLS、证书续期、DNS、路由和代理由你管理。插件不会安装隧道组件、部署 VPS、修改代理/防火墙/路由器,也不会为该提供方发起公网探测。
21
21