dsh-mobile 0.5.0 → 0.5.2

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,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.
@@ -39,6 +41,8 @@ The computer-side gateway terminates TLS with a self-signed CA valid for five ye
39
41
  | `frp_attach_cert_unknown` | The self-signed certificate is absent or unreadable. Inspect the panel's certificate status and the private `remote/ingress/` files; do not bypass fingerprint validation. |
40
42
  | `frp_ingress_ca_expired` | The pinned CA expired. Reconfigure the self-signed entry and pair the phone again after checking the new fingerprint. |
41
43
  | Browser reports an untrusted certificate | Expected for the self-signed entry. Use the 0.4.6 Android app and explicit pairing; use public-CA mode for a browser. |
44
+ | `frp_proxy_name_in_use` | frps keeps proxy names unique across **all** its clients, and this installation's own name (`dsh-mobile-<first 12 characters of the installation identity>`) is already registered — usually another DSH computer, or this computer's previous session before the frps heartbeat expires it. Disable self-hosted FRP there, or remove that proxy on the frps. frpc keeps running without publishing the entry port, so before this code the failure only ever appeared as a start timeout. |
45
+ | `frp_remote_port_in_use` | Another proxy on the same frps already owns the chosen entry port. Ports are first-come, first-served per server, so give this computer a different `publicPort` and allow it in the firewall. |
42
46
  | Public entry unreachable | Check the chosen port, cloud and host firewalls, frps listener address, running `frpc`, and the external-network probe. A computer-side probe is not proof that a phone can connect. |
43
47
 
44
- **Remove FRP completely** deletes only plugin-managed files on the computer, including the local `frpc` configuration and self-signed ingress material. The attach path never deletes or restarts your existing frps, Caddy site, certificates, or firewall rules on the VPS. Managed deployment and its separate server cleanup are described in the [self-hosted FRP guide](SELF_HOSTED_FRP.en.md).
48
+ **Remove FRP completely** deletes only plugin-managed FRP files on the computer, including the local `frpc` configuration and self-signed ingress material. The non-secret plugin `installation-id` remains so a later FRP connection keeps the same proxy name; removing all DSH Mobile private state removes that identifier too. The attach path never deletes or restarts your existing frps, Caddy site, certificates, or firewall rules on the VPS. Managed deployment and its separate server cleanup are described in the [self-hosted FRP guide](SELF_HOSTED_FRP.en.md).
@@ -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 的监听;若它不满足所选入口档的要求,插件不会代你修改。
@@ -90,9 +92,13 @@ curl -k -sS -o /dev/null -w '%{http_code}\n' https://YOUR_PUBLIC_IPV4:33080/mobi
90
92
  | `frp_ingress_ca_expired` | 自签 CA 已过期,插件不会静默替换受信任 CA;重新生成 CA 后,手机须核对新指纹并重新配对。 |
91
93
  | 手机浏览器提示证书不受信任 | 自签档的正常现象;请在 App 内配对使用 |
92
94
  | 自检显示「公网入口不可达」 | 端口未放行、frpc 未启动,或 frps 未把该 `remotePort` 转发出来 |
95
+ | `frp_proxy_name_in_use` | frps 的代理名在**整台服务器**上唯一。本机安装名(`dsh-mobile-<安装标识前 12 位>`)已被占用:多半是另一台 DSH 电脑,或本机上一次连接尚未等到 frps 心跳超时。到那台机器上关闭自建 FRP,或在 frps 上移除该代理。frpc 此时仍在运行、只是入口端口没被发布,所以在此之前只会表现为「公网端点未能就绪」。 |
96
+ | `frp_remote_port_in_use` | 同一台 frps 上该入口端口已被别的代理占用(端口先到先得)。给这台电脑换一个 `publicPort`,并在防火墙/安全组放行。 |
93
97
  | App 报「连接到另一台 DSH」 | 公网入口指向了别的 DSH:检查 `remotePort` 与 frpc 是否在本机运行 |
94
98
 
95
99
  ## 与其他通道的关系
96
100
 
97
101
  - **`origin` 自有反代通道**(默认 3444)是另一条独立路径,TLS 由**你自己的外部反代**终止,与本档互不影响。
98
102
  - **deploy 模式**(由插件安装 frps + Caddy)保持不变,仍需要 SSH;attach 模式**零 SSH**。
103
+
104
+ 本机的「彻底移除 FRP」只清理插件管理的 FRP 文件,包括 frpc、私有配置和自签入口材料。不含密钥的插件 `installation-id` 会保留,以便以后重连时沿用同一代理名;清理全部 DSH Mobile 私有状态时也会移除它。此操作不会删除或重启 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
 
@@ -41,7 +41,7 @@ The SSH user, port, and private-key path are kept only in this browser's `localS
41
41
 
42
42
  ## Clean up the VPS
43
43
 
44
- The local **Remove FRP completely** action removes only the computer's managed frpc, token, and configuration; it does not touch the VPS. Server cleanup has two equivalent paths, and both remove only DSH Mobile-owned files, services, and tagged firewall rules:
44
+ The local **Remove FRP completely** action removes only the computer's managed frpc, token, and configuration; it does not touch the VPS. The non-secret plugin `installation-id` remains so a later FRP connection keeps the same proxy name; removing all DSH Mobile private state removes that identifier too. Server cleanup has two equivalent paths, and both remove only DSH Mobile-owned files, services, and tagged firewall rules:
45
45
 
46
46
  1. **Copy the uninstall script**: select **Copy VPS uninstall script**, review it, and run it as root on the VPS. The script stops and removes the frps service and certificate-renewal timer, deletes DSH Mobile configuration, binaries, certificates, and the Caddy snippet, removes the import line from the main Caddyfile while preserving your content, and removes UFW rules carrying the DSH Mobile marker. It deletes the `dsh-mobile` system user only when this deployment created it; an existing user is kept and reported.
47
47
  2. **One-click cleanup**: select **Remove DSH Mobile from the VPS**. The panel verifies the host keys again and runs the same script over pinned SSH after confirmation.
@@ -53,14 +53,18 @@ 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
 
66
+ When several computers share one frps, remember that proxy names are unique across the **whole server** and entry ports are first-come, first-served. The plugin registers an installation-derived name (`dsh-mobile-<first 12 characters of the installation identity>`), so two computers no longer compete for the same name. "A proxy with this installation name is already in use" means that name belongs to another computer, or to this computer's previous session before the frps heartbeat expired it; "the entry port is already occupied" means another proxy holds that port, so give this computer a different one. In both cases frpc stays alive without ever publishing the entry port, which is why the panel previously reported only "the public endpoint did not become ready".
67
+
64
68
  ## Limits
65
69
 
66
70
  - An unregistered domain on a mainland-China VPS may be intercepted by the cloud provider; use public IPv4 mode in that case.
@@ -69,11 +73,6 @@ On the computer, start with the plugin log at `$DSH_HOME/mobile-access/logs/dsh-
69
73
  - VPS SSH targets currently cannot use IPv6.
70
74
  - 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
75
 
72
- ## Manual end-to-end checklist (before release)
76
+ ## Acceptance check
73
77
 
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).
78
+ 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
 
@@ -45,7 +45,7 @@ SSH 用户、端口和私钥路径只保存在当前浏览器的 `localStorage`
45
45
 
46
46
  ## 清理 VPS
47
47
 
48
- 本机“彻底移除 FRP”只删除电脑端的 frpc、Token 与配置,不动 VPS。清理 VPS 有两种方式,都只删除 DSH Mobile 明确拥有的文件、服务与带标记的防火墙规则:
48
+ 本机“彻底移除 FRP”只删除电脑端的 frpc、Token 与配置,不动 VPS。不含密钥的插件 `installation-id` 会保留,方便以后重连时沿用同一代理名;清理全部 DSH Mobile 私有状态时也会移除它。清理 VPS 有两种方式,都只删除 DSH Mobile 明确拥有的文件、服务与带标记的防火墙规则:
49
49
 
50
50
  1. **复制卸载脚本**:点“复制 VPS 卸载脚本”,审阅后以 root 身份在 VPS 上执行。脚本会停用并删除 frps 服务与证书续期定时器、删除配置/二进制/证书文件与 Caddy 片段、从主 Caddyfile 里删掉那一行 import(你自己的内容原样保留;文件删空时留一句占位注释)、删除带 DSH Mobile 标记的 UFW 规则。只有本次部署创建的 `dsh-mobile` 系统用户才会被删除,之前就存在的会被保留并明确告知。
51
51
  2. **一键清理**:点“清理 VPS 上的 DSH Mobile”,同样先核对主机指纹,确认后通过 pinned SSH 执行同样的脚本。
@@ -57,14 +57,18 @@ 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
 
70
+ 一台 frps 被多台电脑共用时:代理名在**整台服务器**内唯一,公网入口端口同样先到先得。插件按本机安装标识注册代理名(`dsh-mobile-<安装标识前 12 位>`),不同电脑之间不会再抢同一个名字;若报「已有本机安装名对应的 FRP 代理在使用中」,说明该名字被另一台电脑占用,或本机上一次连接尚未等到 frps 心跳超时,处理后再重连;若报「入口端口已被占用」,为这台电脑换一个入口端口即可。frpc 遇到这两种冲突时并不会退出,只是入口端口从未发布,修复前面板只会显示「公网端点未能就绪」。
71
+
68
72
  ## 限制
69
73
 
70
74
  - 中国大陆 VPS 上的未备案域名可能被云厂商拦截,此时改用公网 IPv4 模式。
@@ -73,11 +77,6 @@ curl -vk https://PUBLIC_HOST/
73
77
  - VPS 的 SSH 目前不支持 IPv6 地址。
74
78
  - frps 明文 vhost 必须只监听 `127.0.0.1`;插件会拒绝公网可达的明文端口,并在公开发现接口确认是当前电脑后才显示“已就绪”。
75
79
 
76
- ## 手动端到端验证清单(发布前)
80
+ ## 上线前验收
77
81
 
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 拥有的路径与规则(单元测试断言 + 真机复核)。
82
+ 部署后,请在你的实际 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