
在 Android 上把 Termux 当成一台随身的常驻小服务器是我这几年折腾得最多的一件事。手机不像电脑它随时会被系统掐死后台、随时会进入省电休眠你辛苦敲起来的 sshd、crond、静态 Web 服务锁屏一晚上第二天就全没了。所以“Termux 服务自启动”这件事本质上不是简单地写个脚本丢进去而是要跟 Android 的进程管理、电池策略、应用沙箱几套机制打交道。这篇文章我打算把自己反复试错后沉淀下来的一整套方案讲清楚从最核心的 Termux:Boot 开机触发到 termux-services 的守护进程管理再到 wake-lock、日志自愈和排查套路。不管你是想让 SSH 常驻、想让定时任务跑起来还是想在 Termux 里跑 proot 容器顺带把里面的服务带起来这套逻辑都能直接抄。适合刚接触 Termux 的新手也适合已经能把服务跑起来、但总在“重启后就掉”这一步卡住的老玩家。1. Termux 服务自启动的整体设计与方案选型1.1 为什么 Android 上的“开机自启动”是个半真命题先把一个概念掰开说。在桌面 Linux 上我们有 systemd、有 rc.local、有 init 脚本开机流程是明确的、可控的。Android 不是这样它基于 Linux 内核但上层跑的是自己的应用框架普通应用根本没有传统意义上的 init 阶段。你装一个 Termux它就是一个被系统当作“普通 App”管理的进程跟微信、浏览器在法律地位上没有任何区别系统想回收就回收。这意味着两件事。第一真正的“开机自启”必须依赖一个能监听系统启动广播的组件在 Android 里这个广播叫BOOT_COMPLETED只有声明了接收它的应用才能在被系统拉起时执行代码。Termux 主程序本身不干这件事官方的做法是单独出一个Termux:Boot插件来承接。第二即便服务起来了它也只是“App 里的一个子进程”一旦 App 被冻结或杀死服务随之消失所以还得配合 wake-lock 和电池白名单来延长它的存活时间。理解了这两点后面所有配置就都顺理成章了——我们做的不是“让服务活一辈子”而是“让服务在系统的每一次清理之后尽可能自己爬起来”。1.2 三套主流方案各自的定位与取舍目前社区里能落地的方案主要有三条路线我按适用场景给你排一下别一上来就纠结用哪个先看你要解决的是什么问题。方案触发时机解决的问题是否需要 root典型用途Termux:Boot手机开机、App 被拉起时真正意义上的开机自启否sshd、常驻脚本、唤醒后初始化termux-servicesTermux 会话启动时会话内的服务守护、崩溃拉起否sshd、crond、自建服务统一管理termux-job-scheduler系统调度、周期触发周期性任务、延迟任务否定时同步、轮询脚本Termux:Boot 管的是“开机这一下”termux-services 管的是“会话内服务的生命周期”termux-job-scheduler 管的是“定时和周期”。这三者不是互斥的实际生产中我基本是Termux:Boot 写一个开机脚本脚本里用 sv 把 termux-services 的服务统一拉起来两套机制串成一条链。至于 termux-job-scheduler只有在你要跑严格周期任务时才引入它的调度精度受系统 Doze 影响不能当精确 cron 用。1.3 我最终推荐的组合架构说下我目前在用的架构你可以直接照搬思路。开机脚本只做三件事申请 wake-lock、拉起 termux-services 里已经 enable 的服务、把关键动作写进日志。所有的服务定义、依赖关系、重启策略全部交给 termux-services 的 runit 体系去管因为 runit 天生就是干这个的——服务挂了它会自动重启sv status一条命令就能看全部状态。这么做的好处是职责清晰开机脚本短小、不容易写错服务的细节都在 runit 目录里改起来互不影响。反过来如果你把所有逻辑堆在一个开机脚本里一旦某个服务启动失败卡住整条链路就断了排查起来非常痛苦这是我早期踩过的大坑。2. 核心机制拆解Termux:Boot 与 runit 到底做了什么2.1 Termux:Boot 的广播监听与脚本执行链路Termux:Boot 干的事情其实很朴素它在自己的清单里声明接收BOOT_COMPLETED广播系统开机完成后把这条广播发给它它被唤醒然后通过 Termux 的接口执行你放在特定目录下的脚本。这里有个很多人忽略的关键点——安装完 Termux:Boot 之后你必须手动打开它一次。原因是 Android 从某个版本开始对刚安装但从未启动过的应用会限制其后台广播接收能力你不点一下它就不会注册成功脚本自然不执行。脚本存放的目录是固定的~/.termux/boot/。注意在 Termux 的环境里~展开后是/data/data/com.termux/files/home所以完整路径是/data/data/com.termux/files/home/.termux/boot/。这个目录默认可能不存在需要你自己创建。脚本按文件名字母顺序依次执行这一点非常重要如果你有先后依赖就得用10-xxx、20-xxx这样的命名来控制顺序别指望按修改时间排。我见过太多人加了两个脚本一个要先起网络配置一个要后起服务结果因为命名随意导致顺序反了排查半天。2.2 脚本路径、shebang 与执行权限的隐藏规则开机脚本最容易翻车的地方不是逻辑而是格式。三个硬性要求缺一个都静默失败shebang 必须写绝对路径。Termux 不想让你依赖/bin/sh因为它压根不在那个位置。正确的写法是#!/data/data/com.termux/files/usr/bin/sh用 bash 就写#!/data/data/com.termux/files/usr/bin/bash。写错的话系统找不到解释器脚本直接被跳过而且不会有明显报错。必须有可执行权限。写完脚本记得chmod x用ls -l确认一下有没有x位。很多人用编辑器保存后权限是 644脚本就是个摆设。不要用交互式命令。开机执行时没有终端、没有输入任何需要读 stdin 或者依赖交互环境的命令都会挂起把后面所有脚本全部堵死。所以脚本里不要出现read、不要有需要确认的apt交互需要非交互的都得加-y之类的参数。另外提醒一句脚本执行的用户环境和你手动开 Termux 时的环境不完全一致。手动开的时候$PATH、$PREFIX都是齐的开机早期某些变量可能还没设置好。稳妥的做法是在脚本开头显式定义PREFIX和PATH或者干脆用绝对路径调用命令别赌环境变量一定就绪。2.3 termux-services 的 SVDIR 与服务目录结构termux-services 是把 runit 搬到了 Termux 上。runit 是经典的进程管理工具核心理念是每个服务是一个目录目录里放一个run脚本runit 负责执行它并在它退出后重新执行形成守护。Termux 里安装完 termux-services 之后会有一个环境变量SVDIR指向服务目录通常是$PREFIX/var/service/你sv-enable某个服务其实是往这个目录里创建了一个指向系统服务定义的软链接。具体命令的语义要搞清楚别混用sv-enable sshd把 sshd 加入开机自启列表Termux 会话启动时会自动尝试拉起它。sv up sshd立刻启动一次。sv down sshd立刻停止。sv status sshd看当前状态run:表示在跑down:表示停着。sv-disable sshd从自启列表移除。这里有一个极其容易被误解的点termux-services 的“自启”是相对于 Termux 会话而言的不是相对于手机开机。手机重启后如果没有 Termux:Boot 帮忙把 Termux 拉起来termux-services 什么也不会发生。所以你会发现有些人说“我 sv-enable 了怎么重启手机还是没服务”答案就在这里——它没被拉起来。正确思路是用 Termux:Boot 去触发或者至少保证 Termux 会话被启动了一次。2.4 wake-lock 与 Android 后台策略的长期拉锯服务能起来不代表能活下来。Android 的省电策略会在锁屏、长时间无交互、内存吃紧时冻结甚至杀死后台应用。对抗这套机制Termux 提供了termux-wake-lock命令它向系统申请一个 wake lock告诉系统“我还在干活别急着冻我”。这个命令我自己是放在开机脚本最前面执行的因为它需要尽快生效。但 wake-lock 不是万能护身符。从 Android 12 开始系统引入了一个叫 phantom process killer 的东西会监控应用 fork 出来的子进程数量超过阈值就整片干掉。Termux 里跑 proot 容器、跑多进程服务时特别容易触发表现就是运行一段时间后进程莫名全没了日志里也看不出明显异常。解决办法要么是通过 adb 调整系统的进程阈值要么是把服务本身做得更轻、进程更少。这个我在常见问题那一节会展开讲先记住现象服务跑着跑着集体消失且没有报错多半是它干的。3. 从零开始的实操落地3.1 环境准备与安装 Termux:Boot第一步确保你的 Termux 主程序是从正规渠道安装的。不同来源的 Termux 包名和签名可能不同插件和主程序必须匹配否则 Termux:Boot 无法和主程序通信。安装 Termux:Boot 的渠道建议跟主程序保持同一个来源这是保证兼容性最省心的做法。装完之后打开一次 Termux:Boot让它完成初始化然后可以返回桌面。接着回到 Termux 里做两件准备pkg update pkg upgrade -y mkdir -p ~/.termux/boot第一行更新包索引避免后面装东西时碰到依赖冲突第二行创建开机脚本目录。顺手确认一下你打算跑的服务对应的软件包都装好了比如要跑 SSH 就装 opensshpkg install openssh -ymkdir -p里的-p意思是目录已存在也不报错这个习惯值得养成写脚本时经常用得上。到这里环境其实就绪了剩下的都是写脚本和配服务。3.2 编写第一个开机脚本并处理 SSH 首次启动先说一个很多人不知道的细节Termux 里的 sshd 第一次启动前需要生成主机密钥否则会报缺 key。生成命令是所有主机类型一次性生成ssh-keygen -A这条命令会把 rsa、ecdsa、ed25519 等各类主机密钥都生成好放在$PREFIX/etc/ssh/下。生成一次即可之后不用重复。然后写开机脚本。我习惯用带序号的文件名来控制顺序cat ~/.termux/boot/10-startup.sh EOF #!/data/data/com.termux/files/usr/bin/sh termux-wake-lock sv-enable sshd 2/dev/null sv up sshd sv up crond EOF chmod x ~/.termux/boot/10-startup.sh这里用EOF这种写法能避免 shell 提前展开变量比一行行echo追加安全得多。脚本里第一句申请 wake-lock第二句确保 sshd 在自启列表里2/dev/null是为了压掉重复 enable 时的提示后两句分别拉起 sshd 和 crond。chmod x千万别忘。如果你想更直观一点也可以直接用编辑器nano ~/.termux/boot/10-startup.sh写完CtrlO保存、CtrlX退出再补一次chmod x。我个人偏好 heredoc因为可以整个复制粘贴不容易漏字符。3.3 用 termux-services 接管常驻服务开机脚本里只负责“拉”具体怎么守护交给 termux-services。先把包装上pkg install termux-services -y装完之后要完全退出 Termux 再重开一次让它加载新的环境变量SVDIR。判断是否生效看这条命令有没有输出路径echo $SVDIR正常会打印出类似/data/data/com.termux/files/usr/var/service的路径。接下来把服务加进自启sv-enable sshd sv-enable crond状态检查用sv status sshd想停就sv down sshd想临时禁用自启就sv-disable sshd。这里有个实践建议服务目录里最好只留你真正需要的服务。runit 会在会话启动时尝试拉起所有 enable 的服务如果里面塞了个启动就失败的东西日志会一片红影响你排查真正的故障。定期用ls $SVDIR看看有哪些软链接不用的及时sv-disable清理。3.4 两种重启场景的验证方法验证要分两种别混在一起测否则你分不清是哪个环节坏了。第一种只重启 Termux 会话检验 termux-services 是否工作。直接在 Termux 里退出所有会话重新打开然后sv status sshd sv status crond都显示run:就说明会话级自启正常。第二种重启手机检验 Termux:Boot 是否工作。重启后等系统稳定打开 Termux检查脚本有没有执行。最直接的证据是看服务状态或者你可以在脚本里追加一行写日志date ~/boot-log.txt重启后打开~/boot-log.txt如果看到新的时间戳说明脚本确实被触发了。这个日志技巧我强烈建议加上它是区分“脚本没执行”和“脚本执行了但服务没起来”的唯一可靠手段能省下大量瞎猜的时间。3.5 扩展多服务按序启动与延迟处理现实里服务之间常有依赖比如 Web 服务要等网络就绪、要等数据库起来。开机早期网络可能还没完全可用这时候硬启动容易失败。我的处理办法是在脚本里做简单等待或重试而不是一把梭#!/data/data/com.termux/files/usr/bin/sh termux-wake-lock sleep 20 sv up sshd sv up crondsleep 20给系统一点缓冲时间代价是服务晚 20 秒起来但稳定性明显更好。如果你的服务依赖网络还可以用轮询来判断for i in $(seq 1 30); do ping -c 1 -W 2 223.5.5.5 /dev/null 21 break sleep 2 done这段逻辑是每 2 秒试一次网络连通最多等 60 秒连通就跳出循环继续启动服务。用私网或公网地址探测都行重点是把地址换成你确实能访问的。命名上继续用20-、30-前缀区分不同职责的脚本整个目录一眼就能看出执行顺序。4. 常见问题与排查技巧实录4.1 脚本写好却毫无反应六步定位法“我脚本明明写对了重启就是没动静”——这是问得最多的问题。我总结了一套从外到内的排查顺序按这个走基本能定位确认 Termux:Boot 装完后被打开过。没点开过广播注册不生效后面全白搭。确认脚本在~/.termux/boot/目录下不是~/.termux/也不是别的地方。路径错一格就无效。确认 shebang 是绝对路径#!/data/data/com.termux/files/usr/bin/sh这种别写成#!/bin/sh。确认有可执行权限ls -l ~/.termux/boot/看每行有没有x。没有就chmod x。确认脚本单独手动能跑通。在 Termux 里直接sh ~/.termux/boot/10-startup.sh执行一次报错就当场暴露了。确认没被杀后台策略拦下。给 Termux 和 Termux:Boot 都设置电池“无限制”别让系统自动优化它们。这六步里第 1、3、4 是最高频的坑。特别是 shebang很多人从网上抄脚本抄来的路径是对的自己手改的时候少了个/files就永远不执行。4.2 “su program not found”到底在说什么有些热词里会出现类似su -m no su program found on this device. termux does not su的提示这里得把概念讲清楚免得你被误导去装奇怪的东西。su是“切换用户”命令用它需要设备具备提权能力而 Termux 是运行在 Android 沙箱里的普通应用它的权限边界由系统划定本身不提供也不需要su。所以在 Termux 里看到su: not found是完全正常的现象不是你环境坏了。这件事对“服务自启动”的影响在哪在于你要转变思路。Termux 的自启动方案压根不需要 root它靠的是 Termux:Boot 接收系统广播靠的是 termux-services 在应用权限内管理进程全流程合法合规地在沙箱里运行。任何声称“必须提权才能自启”的说法都是走偏了。你要做的就是把上面那套 Boot services 的组合配好该有的效果一点不少。顺带说Termux 里想让服务监听低端口比如 80也会受权限限制改用一个高位端口就能绕开这也是非 root 环境下的常规做法。4.3 服务起来又掉电池优化与进程限制如果你已经确认开机能拉起服务但跑一段时间后又没了那基本是后台策略在起作用。先做软件层能做的给 Termux 设置电池“无限制”关掉它的“智能省电”优化。在开机脚本最前面执行termux-wake-lock。在系统设置里允许 Termux:Boot 后台运行。这些都做完还是掉尤其是 Android 12 及以上就要考虑 phantom process killer 了。它会限制单个应用能 fork 的子进程数量Termux 里跑容器、跑多进程服务特别容易踩线。如果你有条件用 adb 连接电脑调试可以在电脑侧调整阈值属于开发者调试手段具体参数随系统版本略有差异需自行确认。没有 adb 条件的话退而求其次就是精简服务、减少同时 fork 的进程数把能合并的逻辑合并能用单进程的别开多进程这比硬碰硬更现实。4.4 Android 版本差异带来的坑Android 版本跨度大行为差异非常明显这一点在老旧设备上尤其突出。系统版本较低的设备比如 5.1、6 这种在广播投递、后台限制上跟新系统逻辑不同而且新版 Termux 对过低的 Android 版本支持有限可能压根装不上或运行异常这时候要用匹配的老版本别硬套新教程。另外低版本系统对 wake-lock 的限制相对宽松服务反而更容易常驻这是个反直觉但真实存在的情况。Android 12 及以上则是另一头后台管控最严phantom process killer 是新增变量电池优化的默认策略也更激进配置白名单这一步不能省。所以同一套脚本在不同机器上表现不同先别急着怀疑脚本先看系统版本再针对性调整。我在多台设备上验证过配置本身没问题差异几乎都来自系统策略。4.5 常见问题速查表现象最可能原因处理办法重启后脚本完全没执行没打开过 Termux:Boot / shebang 错误 / 无执行权限打开一次插件改绝对路径 shebangchmod x手动跑脚本正常开机不跑目录路径不对 / 后台广播被限确认在~/.termux/boot/给插件设无限制电池sv status 显示 down服务本身启动失败 / 依赖未就绪看$PREFIX/var/log/sv/服务/日志加延迟启动服务跑一阵集体消失phantom process killer / 被冻结精简进程用 adb 调阈值加 wake-locksu: not foundTermux 沙箱内不提供提权属正常无需处理改用非 root 自启动方案重启 Termux 后服务没了只用了 termux-services 没配 Boot用 Termux:Boot 拉起或保证会话被启动这张表我建议截图存着遇到问题先对号入座能省下大量重复检索的时间。表里每一条都是真实踩过的坑不是理论推演。5. 进阶玩法与稳定性加固5.1 日志与自愈让服务挂了能自己爬起来runit 本身有重启能力服务异常退出它会重新拉起但它拉不起来“脚本层面的错误”。所以我会额外加一层自愈。做法是让开机脚本用一个定时循环去定期检查关键服务状态发现 down 就尝试 up#!/data/data/com.termux/files/usr/bin/sh termux-wake-lock while true; do sv status sshd | grep -q ^run: || sv up sshd sleep 300 done 这段逻辑每 5 分钟检查一次 sshd不在运行状态就拉一次末尾让它后台跑。日志方面runit 会把服务输出写到$PREFIX/var/log/sv/服务名/下current是当前日志的软链接用tail -f就能实时看。养成看日志的习惯很多“玄学问题”看一眼日志就真相大白。这里提醒一下自愈循环本身也是个进程进程数不是越多越好只给真正关键的服务加这层保险。5.2 与 proot 容器的配合不少人会在 Termux 里用 proot-distro 装个 Ubuntu 或别的发行版然后在容器里跑服务。这种场景下自启动要分两层理解主机层Termux 本体用 Termux:Boot 拉起一个入口脚本入口脚本再负责启动容器并执行容器内的服务。也就是说容器里的服务不会自己开机启动它的“启动权”掌握在主机层的脚本手里。实操上入口脚本大致是先用proot-distro login进入容器并执行指定命令把容器内的服务带起来。难点在于容器登录是前台会话脚本要处理它的常驻和退出。我的经验是尽量把容器内的服务做成“跑在前台”的形式交给外层脚本托管别在容器里再套一层后台守护否则两层守护互相打架排查难度翻倍。同时容器对进程数更敏感前面说的 phantom process killer 在这里触发概率更高服务设计越精简越好。5.3 定时任务与自启动的边界最后理一下 crond 和 termux-job-scheduler 的边界避免用错工具。crond 跑在 Termux 会话内精度高、写法就是标准 crontab但它依赖会话存活termux-job-scheduler 走的是系统调度应用被杀掉也能触发代价是精度低、受 Doze 影响大。我的建议是要求准时、且服务本来就常驻的用 crond并由自启动体系保证它一直活着要求“即使被清理也要跑”的兜底任务才上 termux-job-scheduler。把两者的定位分清你就不会纠结为什么定时任务有时候不按点跑了——很多时候不是 cron 写错而是承载它的会话根本没起来。我个人在实际操作中的体会是Termux 服务自启动这件事八成的失败都不是因为命令写错而是没搞清楚 Android 到底在哪一层“掐”你的服务。Termux:Boot 负责开机那一下termux-services 负责会话内的守护wake-lock 和电池白名单负责延长存活日志负责告诉你真相——把这四件事各归各位剩下的就是耐心。最后再分享一个小技巧每次改完开机脚本别急着重启手机先在 Termux 里直接手动执行一遍确认逻辑通、权限对、路径准再走真实的开机流程验证。手动能跑通、开机却不跑问题一定在触发层手动都跑不通就是脚本本身的问题。用这个二分法排查速度能快一大截。