把闲置小米手机改成 Ubuntu 服务器

2026年8月30日| Ruichen Zhou| 约 15 分钟阅读

我手里有一台闲置的小米手机,系统是 Android 13,已经安装 Magisk,Termux 也能取得 root 权限。我打算让它长期插电,运行 SSH 和监控程序。

这台手机最后保留了两个 SSH 端口:22 进入 Ubuntu,8022 进入 Termux。平时用 22;Ubuntu 起不来或需要修改 Android 文件时,再用 8022。下面按实际安装顺序来写。递归挂载事故和恢复过程放在下一篇

1. 准备的软件

这次使用的版本如下:

软件 版本或要求
Android 13,已 Root
Magisk 能执行 /data/adb/service.d/ 中的脚本
BusyBox NDK v1.36.1
chroot-distro v2.1.0
Ubuntu 24.04.3 LTS
Termux 已安装 OpenSSH、Termux:API 和 termux-api

脚本可以下载为完整附件包,每个文件的安装位置写在附件说明。附件里的 Wi-Fi 配置是空的,需要换成自己的值;Cloudflare 和监控相关的占位属于组网与监控篇,本文用不到。

不同手机的 Magisk、SELinux、电池管理和 cmd wifi 可能不一样。下面的步骤适合复现这台手机的做法;换机型时,挂载路径、电池控制节点和 cmd wifi 的行为都要先验证再照搬。

2. 安装 BusyBox、chroot-distro 和 Ubuntu

先在 Magisk 中安装 BusyBox NDK,再安装 chroot-distro。两个模块装完后重启手机,否则 chroot-distro 需要的挂载还没有准备好。

进入 Termux,下载并安装 Ubuntu:

chroot-distro download ubuntu
chroot-distro install ubuntu

进入 Ubuntu 后检查版本:

cat /etc/os-release
id

我这里显示 Ubuntu 24.04.3 LTS,当前用户是 root。这里的 Ubuntu 是用 chroot 方式运行的:用户空间放在 Android 的一个目录里,共用 Android 内核,没有普通 Ubuntu 的 systemd,也不能按虚拟机的方式使用独立内核。

安装时遇到过一个容易忽略的问题。我从电脑用 SSH 执行 Termux 命令时,非交互会话里没有平时的 $PREFIX 环境变量,安装命令因此把文件写到了 /bin/chroot-distro,系统拒绝写入。把命令里的 $PREFIX 替换成 /data/data/com.termux/files/usr 后执行正常。

通过 SSH 自动执行 Termux 命令时,不要假定 $PREFIXPATH 和交互终端里完全一样。

3. Ubuntu 里没有 systemd

普通 Ubuntu 可以用 systemctl enable --now ssh 设置开机启动,这个 chroot 里没有 systemd,也没有 journald。sshd、rsyslog、fail2ban 和 Beszel Agent 都需要脚本启动。

我的做法是:Magisk 在 Android 启动后运行 94-ubuntu-services.sh;这个脚本挂载 Ubuntu,然后执行 Ubuntu 里的 /usr/local/sbin/phone-server-services。后一个脚本每 60 秒检查一次 sshd 是否在监听。

94-ubuntu-services.sh 只在首次成功时执行一次 chroot-distro mountphone-server-services 退出后,脚本只重新启动它,不再重复挂载,避免挂载逐次累积;初次挂载失败时会等待 30 秒重试。

附件中的 phone-server-services 默认只启动 sshd。rsyslog、fail2ban 和 Beszel 需要先安装并完成各自配置,再把文件顶部的开关从 0 改为 1。目前这台手机的 rsyslog 和 fail2ban 还没有确认长期正常,因此附件没有默认开启。

附件里的 ENABLE_BESZEL 保持为 0,不包含任何凭据。复现这台手机已有的 Beszel 监控时,先在 Beszel Hub 中新增 phone-server,把 Hub 生成的 /etc/default/beszel-agent 放入 Ubuntu,再把设备上 /usr/local/sbin/phone-server-services 实际副本中的 ENABLE_BESZEL 改为 1。

4. 配置两个 SSH 端口

端口 程序 什么时候使用
22 Ubuntu 的 sshd 日常登录、运行 Ubuntu 命令
8022 Termux 的 sshd Ubuntu 无法启动时修改 Android 或 Magisk 文件

先在 Ubuntu 中安装 OpenSSH Server 和 sudo

apt update
apt install -y openssh-server sudo nano

创建普通用户,并让它可以使用 sudo

adduser <用户>
usermod -aG sudo <用户>

为这个用户创建 SSH 目录:

install -d -m 700 -o <用户> -g <用户> /home/<用户>/.ssh
nano /home/<用户>/.ssh/authorized_keys
chown <用户>:<用户> /home/<用户>/.ssh/authorized_keys
chmod 600 /home/<用户>/.ssh/authorized_keys

把客户端的公钥写入 authorized_keys。下一步先启动 sshd,确认普通用户可以通过公钥登录,再关闭 root 和密码登录。

Ubuntu 没有 systemd,第一次启动 sshd 时要自己创建运行目录:

install -d -m 755 /run/sshd
/usr/sbin/sshd -t
/usr/sbin/sshd

保留当前的 Termux 8022 会话,再从另一台设备测试 Ubuntu 22。确认公钥登录成功后,编辑 /etc/ssh/sshd_config,加入或修改:

PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no

可以用下面的命令查看 sshd 最终采用的值:

sshd -T | grep -E 'permitrootlogin|passwordauthentication|kbdinteractiveauthentication'

语法没有问题后,让正在运行的 sshd 重新读取配置:

/usr/sbin/sshd -t
kill -HUP "$(cat /run/sshd.pid)"

我第一次检查时出现过“密码仍然能登录”的假象。原因是 macOS 复用了已经登录过的 SSH ControlMaster 连接,新的终端并没有重新认证。重新测试时要禁用连接复用:

ssh -o ControlMaster=no -o ControlPath=none <>@<手机地>

禁用复用后,密码登录被拒绝,公钥登录成功。

早期的开机脚本还用过 pgrep -f /usr/sbin/sshd 检查 sshd。这个命令可能匹配到正在执行检查的命令本身,于是脚本以为 sshd 已经启动。后来改为检查 22 端口是否在监听。

5. 设置 ACC 充电限制

手机长期接电,我用 ACC(Advanced Charging Controller,按电量和温度控制充电的 Magisk 模块)限制充电,安装与配置方法沿用手机搭建服务器第二期。我在 ACC 中使用下面的参数:

  • 电量低于 75% 时恢复充电;
  • 电量达到 85% 时暂停充电;
  • 温度达到 45°C 时停止充电;
  • 温度降到 40°C 时允许恢复。

设置后检查过一次:手机接着电源,电量高于 85%,系统显示外部电源已连接、充电电流为 0、ACC 状态为 Idle。当时充电已经暂停。至于电池寿命能延长多少,还没有长期数据。

6. 复制开机脚本

需要部署的主要文件如下:

文件 放到哪里 作用
60-termux-wake-keeper.sh /data/adb/service.d/ 开机后启动 wake keeper
94-ubuntu-services.sh /data/adb/service.d/ 挂载一次 Ubuntu,并启动 Ubuntu 内的服务
98-termux-sshd.sh /data/adb/service.d/ 启动 Termux 的 sshd(8022),首次解锁前等待重试
99-phone-server.sh /data/adb/service.d/ 启动 /data/local/wifi-keeper/wifi-keeper.sh
phone-server-services Ubuntu 的 /usr/local/sbin/ chroot 内服务管理脚本,默认只启动 sshd
termux-wake-keeper.sh /data/local/termux-wake-keeper/ 定期刷新 wake lock
wifi-keeper.sh /data/local/wifi-keeper/ 检查 Wi-Fi 和 IPv6,断线时尝试重新连接

termux-wake-keeper.sh 在附件包里;wifi-keeper.sh 的完整脚本来自参考资料中的第四期文章,填入自己的 Wi-Fi 后再放到 /data/local/wifi-keeper/

wake keeper 通过 Termux:API 持有 wake lock(阻止 Android 休眠的锁),并每 60 秒续锁,避免 Android 休眠后杀掉后台任务。

复制完成后设置可执行权限。不要覆盖 service.d 中原有的其他 Magisk 脚本。

Android 侧文件在 Android 的 root shell 中执行:

chmod 755 /data/adb/service.d/60-termux-wake-keeper.sh
chmod 755 /data/adb/service.d/94-ubuntu-services.sh
chmod 755 /data/adb/service.d/98-termux-sshd.sh
chmod 755 /data/adb/service.d/99-phone-server.sh
chmod 755 /data/local/termux-wake-keeper/termux-wake-keeper.sh
chmod 755 /data/local/termux-wake-keeper/stop-termux-wake-keeper.sh
chmod 755 /data/local/wifi-keeper/wifi-keeper.sh

phone-server-services 在 Ubuntu 文件系统内,进入 Ubuntu chroot 后执行:

chmod 755 /usr/local/sbin/phone-server-services

关闭 chroot-distro 默认的 Android 根目录绑定:

chroot-distro android-bind disable

这一步会修改 /data/local/chroot-distro/.config/android_bind。关闭后,Ubuntu 不再把 Android 的 /data 挂进去。

7. 重启后怎样检查

重启手机后要先解锁一次。Termux 的文件放在 Android 凭据加密存储中,首次解锁之前,8022 和 Termux API 都不可用。98-termux-sshd.sh 会等待并重试,但它不能代替人工解锁。

解锁后按下面的顺序检查:

  1. 从另一台机器连接 Termux 的 8022;
  2. 连接 Ubuntu 的 22;
  3. 查看 /data/local/ubuntu-services-boot.log
  4. 查看 Ubuntu 的 /var/log/phone-server-services.log
  5. 在 Ubuntu 里执行 mount | wc -l,隔一段时间再看一次,数字应保持稳定。

如果 8022 能连而 22 不能连,先看 94-ubuntu-services.sh 的日志。如果两个端口都不能连,先确认手机已经解锁、Wi-Fi 正常、Termux 没有被系统清理。

参考资料

手机接入 Tailscale、SSH 配置和监控的步骤写在组网与监控篇

评论