这篇记录如何把一台已经 root 的安卓手机加入自建 frp-panel,重启后恢复连接,并保留明确的停止入口。FRP 通信本身不要求 root;这里使用 Magisk,是为了管理启动、私有配置和 Android 下的运行环境。
本次用的是 frp-panel v0.1.37 的受管客户端。它与直接使用上游 frpc 加 TOML 配置文件的流程不同,不能混用参数。本次手机为 Redmi K60 / mondrian / ARM64;自制模块有机型检查,其他手机需要单独适配。
先准备一个设备身份
在自己的面板中为手机创建独立客户端,领取它自己的 ID、Secret、API URL 和 RPC URL。手机只保存这台设备所需的凭据。先让客户端上线,保持零隧道;等确实要访问某个本机服务时,再配置代理、目标端口和应用鉴权。
以下全部是占位值。URL 应以你自己的服务端配置为准;示例的 WSS 要求服务端确实提供相应入口,不能仅把任意 RPC 地址前缀改成 WSS。
CLIENT_ID='REPLACE_WITH_DEVICE_ID'
CLIENT_SECRET='REPLACE_WITH_DEVICE_SECRET'
CLIENT_API_URL='https://frp.example.com'
CLIENT_RPC_URL='wss://frp.example.com'
CLIENT_TLS_INSECURE_SKIP_VERIFY=false
CLIENT_FEATURES_ENABLE_REMOTE_SHELL=false
CLIENT_FEATURES_ENABLE_FUNCTIONS=false
LOGGER_DEFAULT_LOGGER_LEVEL=info
LOGGER_FRP_LOGGER_LEVEL=warn
保存为 frp-client.private.env。这些字段可在该版本的 官方配置定义中核对。本例显式开启证书校验,关闭远程 Shell 和 Functions。配置会由启动脚本按 shell 环境文件读取,因此只使用自己管理的配置内容。
确认二进制能在手机上执行
从官方发布页下载对应架构的客户端,核对发布文件的 SHA256,再取到手机。Linux ARM64 静态 ELF 并不保证兼容每一台安卓;帮助信息能运行,只能证明最基本的执行条件。
adb shell getprop ro.product.cpu.abi
adb push frp-panel-linux-arm64 /data/local/tmp/
adb shell chmod 700 /data/local/tmp/frp-panel-linux-arm64
adb shell /data/local/tmp/frp-panel-linux-arm64 client --help
本次候选文件的 SHA256 为:
47b7cb37a25eb742579ff2cc87e13b033c0816eca24b98286cafcce2646289bb
版本变化后应重新核验文件,不能继续沿用这个哈希。
配置、程序与日志分别放好
本次把二进制和监督脚本放进 Magisk 模块,私有配置放在 /data/adb/bismih-mondrian。目录权限为 700,配置与日志为 600,程序和脚本为 700。公开模块中不含任何设备凭据。
/data/adb/modules/bismih_mondrian/
module.prop
service.sh
namespace.sh
supervisor.sh
control.sh
bin/frp-panel-linux-arm64
/data/adb/bismih-mondrian/
frp-client.private.env
logs/
run/
通过 ADB 调试安装时,可以先把配置放到临时目录,再使用已授权的 su 复制到私有目录。核对复制成功后,删除临时副本。不要把真实密钥写进聊天、公开源码或博客截图。
adb push frp-client.private.env /data/local/tmp/
adb shell '/debug_ramdisk/su -c "mkdir -p /data/adb/bismih-mondrian"'
adb shell '/debug_ramdisk/su -c "chmod 700 /data/adb/bismih-mondrian"'
adb shell '/debug_ramdisk/su -c "cp /data/local/tmp/frp-client.private.env /data/adb/bismih-mondrian/"'
adb shell '/debug_ramdisk/su -c "chmod 600 /data/adb/bismih-mondrian/frp-client.private.env"'
adb shell rm /data/local/tmp/frp-client.private.env
这些命令只放入配置,不会凭空生成模块脚本。模块源码与构建方式见下方下载说明。当前包仅适用于本文的 mondrian,不是所有 root 手机都能直接安装的通用包。
本文使用的模块为 1.1,仅适配 mondrian。下载模块脚本源码与构建工具(约 9 KB,无二进制和凭据)。解压后先阅读 README.txt,运行 python3 build_module.py,工具会从官方发布地址下载固定版本的两个 ARM64 程序、检查哈希并生成可安装 ZIP;在 Magisk 的模块页安装生成的 ZIP,写入自己的私有配置后重启。源码包 SHA256:1d94fb8f8b379173396e2f6679ca3c5ba7c474afd02e94cbb043371adbfeb5f4。两个上游程序各自遵循其许可证;公开源码包没有重新分发它们的二进制。
处理 Android 的 DNS、证书和时钟
安卓的 DNS 机制与普通 Linux 不完全一样。这台设备缺少供 Linux Go 程序使用的 /etc/resolv.conf,手机时钟还曾停在几个月前。分别检查网络是否已连接、域名能否解析、系统时间是否正确,才能判断真正的故障点。
本次用私有挂载命名空间加一个最小兼容目录,为服务进程提供独立的 resolv.conf,并映射实际的系统证书目录;不改 Android 全局 DNS。这里的兼容目录不是安全沙箱,网络和 proc 指标仍来自真实手机。SELinux 保持 Enforcing,TLS 校验保持开启。
export SSL_CERT_DIR=/apex/com.android.conscrypt/cacerts:/system/etc/security/cacerts
export GOMAXPROCS=2
如果根本没有可用 Wi-Fi 或移动数据,增加 DNS 文件也不会让手机联网。临时测试已经出现过这种情况,因此不能把所有连接失败都归咎于证书或程序。
让 Magisk 管理一个可停止的服务
根据 Magisk 的启动脚本文档,后台服务放在模块的 service.sh,使用 late_start 阶段。这里不再往 service.d 加第二份启动器。
本次模块等待系统启动完成,再启动监督器;用 PID 与进程启动时间避免重复实例和误杀,进程退出后按 5 至 60 秒退避重启,每隔几秒检查日志体积和停止标志。网络重连由 frp 客户端处理,监督器处理的是进程退出。
adb shell '/debug_ramdisk/su -c "/system/bin/sh /data/adb/modules/bismih_mondrian/control.sh start"'
adb shell '/debug_ramdisk/su -c "/system/bin/sh /data/adb/modules/bismih_mondrian/control.sh status"'
adb shell '/debug_ramdisk/su -c "/system/bin/sh /data/adb/modules/bismih_mondrian/control.sh stop"'
模块可只配置 frp,也可同时配置 Komari。若两者都配置,当前动作按钮和上述 stop 会同时停止这两个服务;它们共用一套监督器,不需要安装两份模块。手动停止状态会保留,需再次 start 才恢复。
还有一个与客户端无关的故障:系统把当前 Wi-Fi 判为“无互联网”,把保存的配置永久禁用,导致重启后不自动连接。本次确认 HTTPS 实际可达后,记住“仍然连接”并重新启用该配置;修复后息屏关闭 Wi-Fi 12 秒再打开,约 6.3 秒自动连回,之后重启也能自动连接。仅为这个网络保存选择,没有关闭全局网络验证。其行为可对照 Android 的无互联网网络确认界面源码。
怎样判断是真的接入成功
| 观察 | 能够说明什么 |
|---|---|
| 帮助命令成功 | 二进制能够执行 |
| 进程存活 | 客户端尚未退出,不代表服务器连接成功 |
| 面板显示独立客户端在线、心跳持续刷新 | 受管客户端连接已建立 |
| 零隧道 | 仅加入面板时的预期配置,不表示已经提供某个远程服务 |
| 指定服务的端到端访问成功 | 另行配置的那条隧道和目标服务可用 |
上线后应断开 USB,锁屏观察,再做一次短暂断网、恢复网络和手机重启。记录恢复时间、进程数量、日志和耗电情况,不能因为电脑连着时成功就宣称脱机常驻可靠。
停止、停用和卸载
临时停止使用 control.sh 或模块动作按钮;长期停用使用 Magisk 的停用开关。卸载模块时清理本机私有配置。面板中的设备身份是另一部分资源,永久停用时可在面板撤销或删除该身份;仅删除手机文件不会自动让服务端凭据失效。
本次已完成受管客户端接入,没有为手机开放公网 ADB、root SSH 或任意文件端口。要增加隧道,应逐项确认要访问的本机服务和访问权限。
本次实测记录(2026-10-16)
| 项目 | 结果 |
|---|---|
| Android 环境 | LineageOS 24 / Android 17、Magisk 30.7、UID 0、SELinux Enforcing |
| 连接 | 服务端连续两次确认独立客户端在线;DNS 和 HTTPS/WSS 工作,未跳过证书校验 |
| 隧道 | 实际设备配置 1 份,0 proxies、0 visitors;未做隧道端到端吞吐测试 |
| 断网恢复 | 息屏 Wi-Fi 关闭 12 秒再打开,约 6.3 秒重新连接,之后服务端确认恢复在线 |
| 重启 | 未手动启动客户端,模块恢复进程,服务端再次确认在线 |
| 控制 | stop、disable 使两个进程停止;卸载脚本删除私有目录;恢复配置后正常启动 |
| 防多开 | 重复 start 保持原监督器;旧系统另做过进程崩溃恢复测试 |
本次短时测试全程由 USB 供电,验证了息屏、断网、重启和控制脚本。尚未做拔线后的长时间深度休眠或耗电对照,因此不能据此保证全天在线或某个续航数值。
