Turn any Android phone or tablet into an autonomous fleet worker node using Termux.
After setup, the device auto-starts on boot:
- SSH server (port 2222) — passwordless access from your workstation
- Worker daemon (port 9003) — HTTP API for fleet task execution
- Fleet registration — heartbeat to fleet orchestrator
- Wake lock — prevents Android from killing services
| Device | RAM | CPUs | Status |
|---|---|---|---|
| Samsung Galaxy J7 (SM-J727V) | 1.8 GB | 4 | Working |
| Blackview Tab 7 Pro (L381) | 7.4 GB | 8 | Working |
- Termux from F-Droid (NOT Google Play — the Play version has background execution limits)
- Termux:Boot from F-Droid (enables auto-start on boot)
- USB debugging enabled on the device
- ADB installed on your workstation
# Connect device via USB, then:
./setup.sh my-device-name ~/.ssh/id_rsa.pub
# Follow the on-screen instructions to run the setup command in TermuxIf the automated setup doesn't work on your device:
# 1. In Termux on the device:
pkg update -y && pkg install -y openssh python iproute2
# 2. From your workstation, push your SSH key:
adb push ~/.ssh/id_rsa.pub /sdcard/pubkey.txt
# 3. In Termux:
termux-setup-storage
mkdir -p ~/.ssh
cp ~/storage/shared/pubkey.txt ~/.ssh/authorized_keys
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
# 4. Copy worker files to Termux home (via SSH or adb push + cp)
# 5. Set up boot script:
mkdir -p ~/.termux/boot && chmod 700 ~/.termux/boot
cp start-worker ~/.termux/boot/start-worker
chmod +x ~/.termux/boot/start-worker
# 6. Edit hostname in ~/.termux/boot/start-worker
# 7. Change SSH port:
sed -i 's/#Port 8022/Port 2222/' $PREFIX/etc/ssh/sshd_config
# 8. Start services:
sshd && python -B worker-daemon.py &# Health check
curl http://<device-ip>:9003/health
# Execute a command
curl -X POST http://<device-ip>:9003/execute \
-H "Content-Type: application/json" \
-d '{"command": "python3", "args": ["-c", "print(\"Hello!\")"]}'
# Deploy a file
curl -X POST http://<device-ip>:9003/deploy \
-H "Content-Type: application/json" \
-d '{"filename": "script.py", "content": "print(\"deployed\")"}'| File | Purpose | Deployed To |
|---|---|---|
worker-daemon.py |
HTTP worker daemon | ~/worker-daemon.py |
worker-register.sh |
Fleet registration + heartbeat | ~/worker-register.sh |
start-worker |
Boot auto-start script | ~/.termux/boot/start-worker |
setup.sh |
Automated setup via ADB | Run from workstation |
- Battery optimization disabled for Termux and Termux:Boot
- WiFi sleep policy set to "never"
- WiFi suspend optimizations disabled
SSH connection refused after screen off: WiFi may be dropping. Verify settings:
adb shell settings get global wifi_sleep_policy # should be 2
adb shell settings get global wifi_suspend_optimizations_enabled # should be 0
adb shell dumpsys deviceidle whitelist # should list com.termuxsshd dies in background:
Ensure termux-wake-lock is running (included in boot script). Check that battery optimization is disabled for Termux.
Worker daemon port in use:
The daemon retries with exponential backoff (3s, 5s, 10s, 15s, 20s). If it still fails, kill old processes: pkill -9 python
Termux:Boot not auto-starting: Launch Termux:Boot once manually to register the boot receiver. It has no UI — it opens and closes immediately.
F-Droid vs Play Store Termux: The Google Play version of Termux is incompatible with F-Droid add-ons (different signing keys) and has stricter background execution limits. Always use the F-Droid version for fleet workers.
Crush is an AI coding CLI from charm.sh that runs natively on Android/Termux.
ssh -p 2222 <device-ip>
# Download the Android arm64 build
curl -sL https://github.com/charmbracelet/crush/releases/latest/download/crush_Linux_arm64.tar.gz -o /tmp/crush.tar.gz
# Extract and install
tar xzf /tmp/crush.tar.gz -C /tmp
cp /tmp/crush $PREFIX/bin/crush
chmod +x $PREFIX/bin/crush
rm /tmp/crush.tar.gz /tmp/crushAdd to ~/.bashrc:
export OPENROUTER_API_KEY="your-key"
export GOOGLE_API_KEY="your-key"
export GROQ_API_KEY="your-key"
export CEREBRAS_API_KEY="your-key"
export DEEPSEEK_API_KEY="your-key"
export COHERE_API_KEY="your-key"Then reload: source ~/.bashrc
Create ~/.config/crush/crush.json:
{
"providers": {
"openrouter": {
"apiKey": "$OPENROUTER_API_KEY",
"baseURL": "https://openrouter.ai/api/v1"
},
"google": {
"apiKey": "$GOOGLE_API_KEY"
},
"groq": {
"apiKey": "$GROQ_API_KEY"
},
"cerebras": {
"apiKey": "$CEREBRAS_API_KEY"
},
"deepseek": {
"apiKey": "$DEEPSEEK_API_KEY",
"baseURL": "https://api.deepseek.com/v1"
},
"cohere": {
"apiKey": "$COHERE_API_KEY",
"baseURL": "https://api.cohere.com/compatibility/v1"
}
}
}- Hyper model routing: Crush's Hyper system (
hyper.charm.land) auto-selects OpenAI models regardless of config. The data store at~/.local/share/crush/crush.jsonoverrides provider config. Remove it to reset, but it regenerates on launch. - Context length: Some models (e.g. Cerebras
zai-glm-4.7) have 8K context limits that Crush's system prompt exceeds (~11K tokens). Use models with larger context windows. - proot-distro: If using Debian via proot-distro on older devices, set
PROOT_NO_SECCOMP=1or proot crashes withIS_IN_SYSENTERassertion.
crush --version
crush # launches interactive mode- Worker daemon has no authentication — suitable for home lab only
- Do not expose port 9003 to untrusted networks
- SSH uses public key authentication only (no passwords)
- Command execution is restricted to an allowlist
GPL v3.0