抽屉里那台吃灰的旧手机,屏幕碎了、电池鼓了、系统卡成 PPT,但你舍不得扔——万一哪天有用呢?
现在它真有用武之地了。
一个 10 月 31 日刚上线的开源项目 termux-containers,让你可以在不 Root、不刷机、不跑虚拟机的前提下,用 Docker Compose 风格的 YAML 配置文件,在安卓手机里跑起 Nginx、Cloudflared、Aria2 这类服务。
听起来像是"把手机变成服务器"的又一个标题党?
我研究了一圈它的实现原理,发现这次真的不太一样。它没有伪造一个 Docker Engine,而是老老实实走 Termux + PRoot-Distro 的路子——不是"兼容 Docker",而是补上 Docker 最缺的那块拼图:声明式多容器编排。
TL;DR
- termux-containers 基于 PRoot-Distro,无需 Root、无需 Docker 守护进程,用 YAML 管理多个 OCI 容器
- 项目 2026-10-31 上线,GitHub 49 stars,作者仅用两个镜像(cloudflared、fast note sync、cli proxy api)做了验证
- 它是"类 Docker Compose"而非"Docker 替代":无端口映射、无内核级隔离、强依赖 ARM64 镜像
- 适合做低功耗常驻小服务(消息机器人、Webhook、下载工具),不适合跑重型应用
- 折腾成本极低(一条命令安装),但要做好"后台被杀"和"镜像架构不兼容"的心理准备
它到底是个什么东西?
先给结论:termux-containers 不是一个容器运行时,而是一个配置管理器。
它自己不拉镜像、不跑容器、不管网络。真正干活的是 Termux 生态里的 PRoot-Distro——一个能在 Android 用户空间里跑 Linux 发行版的工具。termux-containers 做的事情,是给 PRoot-Distro 套上一层"类 Docker Compose"的壳:
services:
web:
image: nginxinc/nginx-unprivileged:stable-alpine
enabled: true
volumes:
- type: directory
source: ./data/web
target: /usr/share/nginx/html
environment:
PORT: "8080"
写一个 YAML,跑一句 termux-containers apply,它就帮你把镜像拉下来、容器建起来、服务跑起来。改完配置再 apply 一次,它会 diff 出变化并重建对应容器。
整个技术栈是四层套娃:
| 层 | 组件 | 作用 |
|---|---|---|
| 1 | Android | 提供 Linux 内核(但应用跑在用户空间) |
| 2 | Termux | 终端模拟器 + 包管理器 + Linux 用户空间 |
| 3 | PRoot-Distro | 用 PRoot 模拟 root,跑 OCI 镜像 |
| 4 | OCI 镜像 | 真正干活的应用(Nginx / cloudflared 等) |
关键点在第 3 层:PRoot 不是 Docker。它不靠内核的 namespace/cgroup 做隔离,而是用 ptrace 在用户空间里"伪造"出一个 root 环境。所以它能跑,但隔离性、性能、兼容性都跟真 Docker 有差距。
上手全流程:从装到跑起来
第一步:装 Termux
去 F-Droid 或 GitHub Releases 装 Termux(Play 商店那个版本已经很久没更新了)。装完打开,先把包管理源换成国内镜像(可选,但强烈建议):
termux-change-repo
然后装基础依赖:
pkg update && pkg install git
第二步:克隆项目并安装
git clone https://github.com/BHznJNs/termux-containers ~/termux-containers
cd ~/termux-containers
bash install.sh
安装脚本会干这几件事:
- 装 Python 3.10+(termux-containers 是 Python 写的)
- 装 PRoot-Distro 及其依赖
- 创建
termux-containers命令入口 - 写一个默认的空
containers.yaml - 配置 Bash Session 自启动(这样每次打开 Termux 都会自动恢复服务)
装完执行 termux-containers --help 确认命令可用。
第三步:写配置
nano ~/termux-containers/containers.yaml
官方示例是 Nginx。我建议第一次跑用 nginxinc/nginx-unprivileged:stable-alpine 这个镜像——它是专门为非 root 环境构建的,体积小(约 40MB), ARM64 支持完善,不会一上来就踩权限坑。
第四步:启动
termux-containers apply
它会读 YAML、拉镜像、建容器、启动服务。完成后:
termux-containers status
看到服务状态是 running 就说明成了。手机浏览器打开 http://127.0.0.1:8080,看到你写的 HTML 页面,那种感觉——一台拿在手里的手机,托管着一个网页——确实挺妙的。
常用命令
| 命令 | 作用 |
|---|---|
termux-containers apply [服务名] |
应用配置:装镜像、启动、重启、停止被禁用的服务 |
termux-containers start [服务名] |
启动已安装且启用的服务(不重新拉镜像) |
termux-containers stop [服务名] |
停止服务,保留容器文件系统和挂载数据 |
termux-containers status [服务名] |
查看实际安装和运行状态 |
termux-containers -f <路径> apply |
用指定配置文件,不局限于默认位置 |
bash uninstall.sh --yes |
卸载工具和自启动入口,保留容器与数据 |
省略服务名表示处理全部配置服务。
它和真 Docker 差在哪?
这是本文最该讲清楚的部分。别指望它跑 Docker Hub 上所有镜像。
差异一:没有内核级隔离
Docker 靠 Linux 内核的 namespace 和 cgroup 做资源隔离。PRoot 是用户空间程序,用 ptrace 拦截系统调用、伪造 root 权限。这意味着:
- 没有真正的进程隔离:容器里的进程和 Termux 共享同一个 PID namespace(虽然 PRoot 会做一层映射)
- 没有资源限制:没有
--memory、--cpus这类限制,一个失控容器能把手机搞卡 - 没有安全边界:容器不是沙箱,跑可信镜像
差异二:没有端口映射
Docker 的 -p 8080:80 是内核级 NAT。PRoot 没这个能力,所以:
- 容器监听的端口就是 Termux 监听的端口
- 手机本地访问
127.0.0.1:8080没问题 - 局域网/公网访问需要额外手段(Cloudflare Tunnel 是最优解)
差异三:镜像架构强绑定 ARM64
Android 手机几乎都是 ARM64。Docker Hub 上很多镜像只提供 amd64,没 arm64。虽然 PRoot-Distro 号称能"拉取后构建镜像",但兼容性不保证。
作者自己在 V2EX 原帖里说测过三个镜像:cloudflared、fast note sync、cli proxy api,都能跑。但这是个 49 stars 的新项目,别拿它跑生产服务。
差异四:后台运行受 Android 摆布
Android 的 Doze 模式、后台限制、电池优化,全都会杀进程。作者提过"手机休眠或系统清理后台时,服务可能中断"。解决办法:
- 手机设置里把 Termux 加入"电池优化白名单"
- 保持 Termux 在前台(开个常驻通知)
- 或者接受"偶尔断"——反正它就是个玩具
我实算的账本:值不值得折腾?
成本侧
| 项目 | 数值 |
|---|---|
| 硬件成本 | 0(闲置手机本来就在抽屉里) |
| 电费 | 手机待机 + 常亮屏幕约 2-5W,按 0.6 元/度算,一天 0.03-0.07 元 |
| 时间成本 | 首次安装 15 分钟(换源 + 拉镜像),后续配置改一次 2 分钟 |
| 镜像体积 | Nginx 约 40MB,cloudflared 约 80MB |
| 存储占用 | 每个容器约 50-200MB,看镜像大小 |
对比一下:一台 N100 小主机 24 小时开着,一年电费约 100-150 元。手机方案的电费可以忽略不计。
收益侧
- 零硬件投入:旧手机本来就是沉没成本
- 便携:随身带一台"服务器",这个场景 N100 做不到
- 低功耗:2-5W vs 6-15W(N100 待机),差距不大但手机赢在"不用买"
- 学习价值:YAML 编排 + PRoot 原理 + OCI 镜像结构,都是可迁移知识
风险侧
- 稳定性:后台被杀、系统更新后 Termux 失效、镜像拉取失败,都属于"预期内会出问题"
- 安全:PRoot 无隔离,跑陌生镜像前请三思
- 维护:项目太新,作者更新频率未知,可能半年后就停更
结论
如果你手边正好有闲置安卓手机,且想找个周末小项目折腾,值得玩。
如果你是为了"稳定跑一个家庭服务",别折腾——买台 N100 或者用云 VPS,省心十倍。
能跑什么、不能跑什么
适合的场景
- 家庭消息转发机器人(Node.js / Python 常驻进程)
- 轻量 Webhook 接收服务
- Aria2 / yt-dlp 下载工具
- Cloudflare Tunnel 客户端(官方示例就是它)
- 简单的 Web 服务器(Nginx / Caddy)
- 临时测试环境(跑个 Redis 练手)
不适合的场景
- 数据库(MySQL / PostgreSQL):PRoot 下 IO 性能差,且无资源限制
- 重型应用(Discourse / Nexus):镜像大、依赖复杂、内存吃紧
- 多用户服务:无隔离,安全边界太薄
- 7×24 生产服务:Android 后台策略不允许
常见问题
Q1: 需要 Root 吗?需要解锁 Bootloader 吗?
A: 都不需要。PRoot 的核心价值就是在用户空间模拟 root,不碰底层权限。
Q2: 和 Termux 里跑 Qemu 虚拟机装 Docker 比,哪个快?
A: termux-containers 快得多。Qemu 是硬件虚拟化,在 ARM 上跑 x86 镜像要走模拟,性能损失巨大。PRoot 是系统调用拦截,开销小一个数量级。作者做这个项目的初衷就是嫌弃 Qemu 太慢。
Q3: 能跑 amd64 镜像吗?
A: 理论上 PRoot-Distro 支持拉取后构建,但兼容性不保证。最稳妥的做法是找官方提供 linux/arm64 的镜像。Nginx、cloudflared、Alpine 系都有 ARM64 版本。
Q4: 手机锁屏后服务会断吗?
A: 会。Android 的 Doze 模式会冻结后台进程。把 Termux 加入电池优化白名单、允许后台活动、保持屏幕常亮(或至少不锁屏),能缓解但不能根除。
Q5: 多个容器之间能通信吗?
A: 能。它们都跑在同一个 PRoot 环境里,共享网络栈。容器 A 监听 8080,容器 B 可以用 127.0.0.1:8080 访问。但没有 Docker 那种自定义 bridge 网络。
Q6: 配置文件里的 PORT 是端口映射吗?
A: 不是。README 里明确写了:"PORT 是应用环境变量,不是端口映射。" 它只是传给容器的环境变量,应用自己决定监听哪个端口。
Q7: 改了镜像 tag 会丢数据吗?
A: 会。README 警告:“修改镜像引用后执行 apply 会重建对应容器,丢失容器内未挂载的数据。” 重要数据务必通过 volumes 挂载出来。
相关阅读
- droidVNC-NG:安卓远程桌面浏览器控制 —— 同样是旧手机再利用,但方向是"把手机当被控端"
- AI Agent 沙箱选型:Docker vs gVisor vs microVM —— 容器隔离性对比,理解 PRoot 和 Docker 差异的背景读物
- MinIO 砍掉开源社区版 Docker 镜像 —— 镜像生态变动如何影响自托管用户
- InstallerX 复活:安卓 APK 安装器与 MT 管理器对比 —— 安卓工具链的另一条思路