深夜提醒

现在是深夜,建议您注意休息,不要熬夜哦~

🏮 🏮 🏮

新年快乐

祝君万事如意心想事成!

share-image
ESC

给 Android SSH 客户端插上 FRP 的翅膀 —— 用手机随时救砖

我在mini主机上安装了 OpenClaw 对接了飞书和微信,有时候他自动升级后就挂了,飞书问问题卡且不回复,但是如果是在外面没法远程家里的机器,回家一查升级配置又变了,整个飞书对接网关挂了,但是又无法SSH连接。
clip_1776681638764_spravj.png
这一刻我才意识到:过度依赖局域网管理本地设备,风险极高。升级任何基础服务前,必须先留好一条「后路」。

为什么传统的远程方案救不了我

事情发生后,我复盘了一下。平时我远程管理家里设备主要依赖以下几条路:

  1. DDNS + 端口映射:因为家里的网络没有固定公网 IP,所以用的是 Cloudflare Tunnel。但是也慢。
  2. Tailscale:组网工具,平时很方便。但是服务在国外,慢且我觉得不安全。
  3. IPv6:运营商给的 IPv6 地址经常变动,而且很多移动网络环境下 IPv6 访问质量不稳定。

一句话:慢,体验差

方案对比:Cloudflare Tunnel vs Tailscale vs FRP

为了不再重蹈覆辙,我决定在另一台独立设备上部署一个「不依赖网关」的远程通道。接下来几天我逐一试了市面上主流的方案:

方案 优点 缺点
Cloudflare Tunnel 零配置、HTTPS 自动证书、免费 依赖 cloudflared 守护进程,网关挂了即失效;国内偶发连接不稳定
Tailscale P2P 直连、组网灵活、免费版够用 需要目标设备在线且运行 Tailscale 客户端;网关离线后内网路由中断
FRP (Fast Reverse Proxy) 自建服务端、完全可控、不依赖网关转发 需要自己维护一台公网服务器;需要配置服务端和客户端

试过一轮之后,我的结论是:

  • Cloudflare TunnelTailscale 都是好产品,但它们的共同点是「依赖目标网络本身的健康状态」。一旦网关/core 设备挂了,这些方案就无能为力。
  • FRP 的优势在于「独立性」。只要被控设备能通电联网(哪怕走手机热点),它就能主动向公网服务器建立反向隧道,完全不需要本地网关参与。

于是我决定:在独立服务器上部署 frps,在所有需要远程救砖的设备上部署 frpc

新问题:FRP 在手机上没法直接用

方案确定后,我很快在家里的 NAS 和软路由上都跑起了 frpc。但很快遇到了一个棘手的问题:

FRP 官方没有提供 Android 客户端。

而我最迫切的场景,恰恰是用手机远程 SSH 到内网设备。现有的 Android SSH 客户端(如 JuiceSSH、Termius、ConnectBot)都不支持 FRP 隧道。

我尝试过一些曲线救国的办法:

  • 在手机上跑 Termux,然后在 Termux 里手动启动 frpc,再用 SSH 客户端连接 127.0.0.1:6000。能跑,但 Termux 后台很容易被系统杀掉,体验极差。
  • 用 VPN 类工具做全局转发,但配置复杂而且不够稳定。

最终我意识到:最优雅的方案,是把 frpc 直接集成到 SSH 客户端里。点击连接主机时,App 自动在后台启动 frpc visitor 隧道,隧道就绪后再建立 SSH 连接。全程对用户透明。

改造 ConnectBot:给老牌 SSH 客户端加上 FRP 翅膀

ConnectBot 是一款老牌的开源 Android SSH 客户端,代码质量高、功能完整、协议支持全面。最重要的是:它是开源的,可以用 Kotlin 直接改。

我的改造思路很简单:

用户点击连接主机

App 检查该主机是否启用了 FRP

如果是,启动嵌入式 frpc visitor 进程

等待本地绑定端口就绪(如 127.0.0.1:6000

SSH 连接到本地绑定地址

断开时自动停止 frpc 进程并清理

核心实现

  1. 嵌入式 frpc 二进制

    我使用 Go 交叉编译了 Android 版的 frpc,以 libfrpc.so 的形式打包进 APK。这样 Android 安装时会自动按 ABI 解压到 nativeLibraryDir,避免了 Android 10+ 对动态提取二进制文件的执行限制。

    GOOS=android GOARCH=arm64 CGO_ENABLED=0 \
    go build -tags noweb -ldflags="-checklinkname=0 -s -w" \
    -o libfrpc.so ./cmd/frpc
  2. FrpManager —— frpc 生命周期管理

    新建了一个 FrpManager 类,负责:

    • 从 APK 中提取/定位 frpc 二进制文件
    • 根据主机配置动态生成 frpc.toml
    • 启动 frpc 进程并轮询等待本地端口就绪
    • 连接断开后自动停止进程、删除临时配置文件
  3. 数据库模型扩展

    Host 实体中新增了 FRP 相关字段:

    • frpEnabled —— 是否启用 FRP 隧道
    • frpServerAddr / frpServerPort —— FRP 服务端地址
    • frpAuthToken —— 认证令牌
    • frpVisitorName / frpServerName —— Visitor 与服务名称
    • frpSecretKey —— STCP 加密密钥
    • frpBindAddr / frpBindPort —— 本地绑定地址和端口
  4. SSH 传输层集成

    SSH.ktconnect() 方法中,如果检测到 frpEnabled,先调用 FrpManager.startVisitor() 建立隧道,然后将 SSH 连接目标从 hostname:port 切换为 frpBindAddr:frpBindPort。断开时自动调用 stopVisitor()

  5. 配置导入导出

    支持通过 JSON 文件批量导入主机配置,一次性把所有内网设备的 FRP 参数配好:

    {
    "hosts": [
    {
    "nickname": "软路由",
    "protocol": "ssh",
    "hostname": "127.0.0.1",
    "port": 22,
    "username": "root",
    "frpEnabled": true,
    "frpServerAddr": "your-server.com",
    "frpServerPort": 7000,
    "frpAuthToken": "your-token",
    "frpVisitorName": "router-visitor",
    "frpServerName": "ssh-router",
    "frpBindAddr": "127.0.0.1",
    "frpBindPort": 6001
    }
    ]
    }

使用体验

改造完成后,整体体验非常流畅:

  1. 打开 App,点击主机列表中的「软路由」
  2. 终端里会先打印 Starting FRP visitor tunnel...
  3. 约 1~2 秒后显示 FRP tunnel ready on 127.0.0.1:6001
  4. 接着自动建立 SSH 连接,输入密码后即可正常操作
  5. 退出会话时,frpc 进程自动停止,不占用后台资源

效果截图:

ConnectBot FRP 配置界面

ConnectBot 终端连接效果

服务端配置参考

整个方案需要三端配合:

1. FRP 服务端(frps)

部署在一台有公网 IP 的服务器上:

bindPort = 7000
auth.method = "token"
auth.token = "your-strong-token-here"

2. 被控端 frpc(软路由/NAS)

serverAddr = "your-server.com"
serverPort = 7000
auth.method = "token"
auth.token = "your-strong-token-here"

[[proxies]]
name = "ssh-router"
type = "stcp"
secretKey = ""
localIP = "127.0.0.1"
localPort = 22

3. 手机端 ConnectBot + FRP

如上面的 JSON 配置所示,每个主机使用不同的 frpBindPort(6000、6001…)避免冲突。

为什么这个方案更可靠

现在再回头看最初的故障场景:

  • OpenClaw 升级导致网关挂了 → 没关系,frpc 跑在 NAS 上,NAS 直连光猫拨号,不依赖网关。
  • 如果 NAS 也挂了 → 软路由上的 frpc 还在,可以 SSH 上去修。
  • 手机热点给设备供网 → frpc 只要能连公网,就能建立隧道。

FRP 的核心优势是「反向连接」:被控设备主动向服务端发起连接,不需要公网 IP,也不需要本地网关做端口映射。只要有一条能出网的链路,就能被远程访问。

项目开源

这个定制版 ConnectBot 已经开源在 GitHub:

monkey-wenjun/connectbot

⚠️ 未在 Google Play 上架,仅在 GitHub Releases 提供 APK 下载。

如果你也有类似的需求 —— 需要在手机上通过 FRP 隧道 SSH 管理内网设备,可以直接下载使用,或基于代码自行定制。

总结

这次「救砖」经历让我深刻体会到:

  1. 任何核心基础设施升级前,先确保有独立的远程通道。不要把所有远程 eggs 放在同一个篮子里。
  2. 自建 FRP 比 Cloudflare Tunnel / Tailscale 更适合「救砖」场景,因为它的反向连接机制不依赖本地网络拓扑的健康状态。
  3. 手机端缺少 FRP 客户端是痛点,但通过改造 ConnectBot 可以优雅解决,体验接近原生。

现在我的架构是这样的:

┌─────────┐      公网      ┌─────────────┐      反向隧道      ┌──────────┐
│ 手机 │ ────────────→ │ FRP Server │ ←──────────────── │ 软路由 │
│(ConnectBot+FRP) │ (frps) │ │ (frpc) │
└─────────┘ └─────────────┘ └──────────┘


┌──────────┐
│ NAS │
│ (frpc) │
└──────────┘

下次再升级 OpenClaw,我可以淡定地坐在咖啡馆里,掏出手机,打开 ConnectBot,连上软路由,一步步排错 —— 而不是在寒风中焦急地赶回家。

文章作者:阿文
文章链接: https://www.awen.me/post/27e55299.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 阿文的博客

评论

0 条评论
😀😃😄 😁😅😂 🤣😊😇 🙂🙃😉 😌😍🥰 😘😗😙 😚😋😛 😝😜🤪 🤨🧐🤓 😎🥸🤩 🥳😏😒 😞😔😟 😕🙁☹️ 😣😖😫 😩🥺😢 😭😤😠 😡🤬🤯 😳🥵🥶 😱😨😰 😥😓🤗 🤔🤭🤫 🤥😶😐 😑😬🙄 😯😦😧 😮😲🥱 😴🤤😪 😵🤐🥴 🤢🤮🤧 😷🤒🤕 🤑🤠😈 👿👹👺 🤡💩👻 💀☠️👽 👾🤖🎃 😺😸😹 😻😼😽 🙀😿😾 👍👎👏 🙌👐🤲 🤝🤜🤛 ✌️🤞🤟 🤘👌🤏 👈👉👆 👇☝️ 🤚🖐️🖖 👋🤙💪 🦾🖕✍️ 🙏💅🤳 💯💢💥 💫💦💨 🕳️💣💬 👁️‍🗨️🗨️🗯️ 💭💤❤️ 🧡💛💚 💙💜🖤 🤍🤎💔 ❣️💕💞 💓💗💖 💘💝💟 ☮️✝️☪️ 🕉️☸️✡️ 🔯🕎☯️ ☦️🛐 🆔⚛️🉑 ☢️☣️📴 📳🈶🈚 🈸🈺🈷️ ✴️🆚💮 🉐㊙️㊗️ 🈴🈵🈹 🈲🅰️🅱️ 🆎🆑🅾️ 🆘 🛑📛 🚫💯💢 ♨️🚷🚯 🚳🚱🔞 📵🚭 ‼️⁉️🔅 🔆〽️⚠️ 🚸🔱⚜️ 🔰♻️ 🈯💹❇️ ✳️🌐 💠Ⓜ️🌀 💤🏧🚾 🅿️🈳 🈂🛂🛃 🛄🛅🛗 🚀🛸🚁 🚉🚆🚅 ✈️🛫🛬 🛩️💺🛰️
您的评论由 AI 智能审核,一般1分钟内会展示,若不展示请确认你的评论是否符合社区和法律规范
加载中...

留言反馈

😀😃😄 😁😅😂 🤣😊😇 🙂🙃😉 😌😍🥰 😘😗😙 😚😋😛 😝😜🤪 🤨🧐🤓 😎🥸🤩 🥳😏😒 😞😔😟 😕🙁☹️ 😣😖😫 😩🥺😢 😭😤😠 😡🤬🤯 😳🥵🥶 😱😨😰 😥😓🤗 🤔🤭🤫 🤥😶😐 😑😬🙄 😯😦😧 😮😲🥱 😴🤤😪 😵🤐🥴 🤢🤮🤧 😷🤒🤕 🤑🤠😈 👿👹👺 🤡💩👻 💀☠️👽 👾🤖🎃 😺😸😹 😻😼😽 🙀😿😾 👍👎👏 🙌👐🤲 🤝🤜🤛 ✌️🤞🤟 🤘👌🤏 👈👉👆 👇☝️ 🤚🖐️🖖 👋🤙💪 🦾🖕✍️ 🙏💅🤳 💯💢💥 💫💦💨 🕳️💣💬 👁️‍🗨️🗨️🗯️ 💭💤❤️ 🧡💛💚 💙💜🖤 🤍🤎💔 ❣️💕💞 💓💗💖 💘💝💟 ☮️✝️☪️ 🕉️☸️✡️ 🔯🕎☯️ ☦️🛐 🆔⚛️🉑 ☢️☣️📴 📳🈶🈚 🈸🈺🈷️ ✴️🆚💮 🉐㊙️㊗️ 🈴🈵🈹 🈲🅰️🅱️ 🆎🆑🅾️ 🆘 🛑📛 🚫💯💢 ♨️🚷🚯 🚳🚱🔞 📵🚭 ‼️⁉️🔅 🔆〽️⚠️ 🚸🔱⚜️ 🔰♻️ 🈯💹❇️ ✳️🌐 💠Ⓜ️🌀 💤🏧🚾 🅿️🈳 🈂🛂🛃 🛄🛅🛗 🚀🛸🚁 🚉🚆🚅 ✈️🛫🛬 🛩️💺🛰️