Termux (Android) install
Run nexo-rs directly on an Android phone under Termux. No Docker, no server — a self-hosted agent in your pocket.
Use this path for a personal agent (one phone, one WhatsApp, one Telegram). For multi-tenant / multi-process deployments the regular Linux setup on a server is the right shape.
Quickest path — pre-built .deb
Once a v* release is published (recipe lives in
packaging/termux/build.sh), download the asset and install with
one command:
# Inside Termux on the phone:
curl -LO https://github.com/lordmacu/nexo-rs/releases/latest/download/nexo-rs_aarch64.deb
pkg install ./nexo-rs_aarch64.deb
The deb pulls the runtime deps Termux already ships (libsqlite,
openssl, ffmpeg, tesseract, python, yt-dlp). Its
postinst scaffolds ~/.nexo/{data,secret} and prints the next
steps. Skip the build-from-source section below if this works.
Root vs non-root
Everything in this guide runs without root. You do not need to root your phone to self-host nexo-rs on it.
Root only unlocks extras:
| Scenario | Needs root? |
|---|---|
| Build + run the agent daemon | ❌ no |
| Pair WhatsApp, Telegram, Google | ❌ no |
Local broker (broker.type: local) | ❌ no |
| Native NATS Go binary | ❌ no (installs to $PREFIX/bin) |
termux-wake-lock, Termux:Boot autostart | ❌ no |
Install skills from pkg (ffmpeg, tesseract, yt-dlp) | ❌ no |
| MCP client / server mode | ❌ no |
Browser plugin via cdp_url to a chromium you launched yourself | ❌ no |
Docker compose stack (via proot-distro or Linux Deploy) | ✅ yes |
| SELinux permissive (if Chromium sandbox misbehaves) | ✅ yes |
| Running multiple proot-distro containers side by side | ✅ yes |
| Bypass Android's battery optimizer more aggressively | ✅ yes |
Short version: don't root just for nexo-rs. Root if you want the full compose stack in a Linux-Deploy chroot, otherwise skip it.
What works
| Area | Status |
|---|---|
| Core runtime, memory, TaskFlow, dreaming | ✅ full |
Broker: type: local (in-process) or native NATS Go binary | ✅ full |
| LLM providers (MiniMax / Anthropic / OpenAI-compat / Gemini) | ✅ all rustls-based |
| WhatsApp plugin (pure Rust + Signal Protocol) | ✅ pairing via Unicode QR |
| Telegram plugin | ✅ Bot API over HTTP |
| Gmail / Google plugin + gmail-poller | ✅ OAuth over HTTP |
| Extensions (stdio + NATS) | ✅ spawn works |
| Skills: fetch-url, dns-tools, rss, weather, wikipedia, pdf-extract, brave-search, wolfram-alpha, summarize, translate | ✅ pure Rust |
| MCP client + server | ✅ stdio + HTTP |
| Health / metrics / admin HTTP servers (8080 / 9090 / 9091) | ✅ unprivileged ports |
What needs a tweak
| Thing | Workaround |
|---|---|
| Service manager (no systemd) | termux-services (runit) or tmux + nohup |
| Run at boot | install the Termux:Boot app + drop a script in ~/.termux/boot/ |
| Survives screen-off | termux-wake-lock (from the Termux:API add-on) before running the agent |
| Browser plugin (Chrome/Chromium) | use cdp_url: to a chromium you start manually with --no-sandbox --disable-dev-shm-usage; or disabled: [browser] if you don't need it |
| Secrets file permission gauntlet | export CHAT_AUTH_SKIP_PERM_CHECK=1 (Android filesystem perms model differs) |
| WhatsApp public tunnel (cloudflared) | skip the public tunnel; pair locally via Unicode QR rendered on the terminal |
| Docker / compose | use broker.type: local or native NATS binary — no containers involved |
Prerequisites
From a fresh Termux install:
pkg update
pkg install -y rust git curl sqlite openssl clang pkg-config
Optional (enables specific skills):
pkg install -y ffmpeg tesseract yt-dlp tmux openssh
Optional (browser plugin):
pkg install -y tur-repo
pkg install -y chromium
Optional (run in background without the terminal session alive):
pkg install -y termux-services termux-api
# install the companion app "Termux:API" from F-Droid
Fast path — bootstrap script
The repo's scripts/bootstrap.sh auto-detects Termux and picks the
right defaults:
git clone https://github.com/lordmacu/nexo-rs
cd nexo-rs
./scripts/bootstrap.sh --yes
What it does on Termux:
- Verifies
rust,git,curl,sqlitefrompkg - Downloads the static
nats-serverGo binary (arm64), drops it in$PREFIX/bin/— or skip with--nats=skipto use the local broker - Creates
./data/**and./secrets/(with Termux-compatible perms) - Stages
config/agents.d/*.example.yaml→*.yamlif missing - Runs
cargo build --release(grab a coffee — ~20–40 min on phone hardware) - Optionally launches
agent setupto pair channels
Expect a ~60–100 MB final binary.
Manual install
1. Install Rust and deps
pkg install -y rust git curl sqlite openssl clang pkg-config
2. Clone and build
git clone https://github.com/lordmacu/nexo-rs
cd nexo-rs
cargo build --release --bin agent
3. Broker
Option A — local (simplest):
# config/broker.yaml
broker:
type: local
persistence:
enabled: true
path: ./data/queue
No NATS binary needed. All pub/sub stays in-process.
Option B — native NATS binary:
curl -L -o /tmp/nats.tar.gz \
https://github.com/nats-io/nats-server/releases/download/v2.10.20/nats-server-v2.10.20-linux-arm64.tar.gz
tar -xzf /tmp/nats.tar.gz -C /tmp
install -m 0755 "$(find /tmp -name nats-server -type f | head -1)" \
$PREFIX/bin/nats-server
nats-server -js &
Go binaries are static and work on Termux without libc surprises.
4. Runtime directories and secrets
mkdir -p ./data/{queue,workspace,media,transcripts} ./secrets
Termux stores files under /data/data/com.termux/files/home by
default. Avoid pointing config paths at /sdcard — Android's
scoped-storage model breaks directory permissions there.
5. Relax the credentials perm check
Android's filesystem doesn't support the same permission bits as Linux in the same way. The credentials gauntlet would refuse to boot with false-positive warnings:
export CHAT_AUTH_SKIP_PERM_CHECK=1
Add it to ~/.termux/termux.properties or a wrapper shell script
so it's set every time.
6. Launch the wizard
./target/release/agent setup
For the WhatsApp pairing step, the wizard renders the QR as Unicode blocks directly in the terminal — scan from the phone's WhatsApp app (Settings → Linked Devices). No public tunnel needed.
7. Run the agent
termux-wake-lock # keep CPU awake even with screen off
./target/release/agent --config ./config
Staying alive in the background
Android's aggressive task killing is the biggest operational surprise. Pick one:
A — termux-wake-lock + foreground notification
termux-wake-lock
# agent in foreground:
./target/release/agent --config ./config
The wake-lock persists until you run termux-wake-unlock or kill
the session. Minimum friction, most reliable.
B — termux-services (runit)
pkg install -y termux-services
sv-enable termux-services
mkdir -p ~/.config/service/nexo-rs
cat > ~/.config/service/nexo-rs/run <<'EOF'
#!/data/data/com.termux/files/usr/bin/sh
cd /data/data/com.termux/files/home/nexo-rs
export CHAT_AUTH_SKIP_PERM_CHECK=1
exec ./target/release/agent --config ./config 2>&1
EOF
chmod +x ~/.config/service/nexo-rs/run
sv up nexo-rs
sv status nexo-rs
C — Termux:Boot (start on device boot)
Install the Termux:Boot app from F-Droid, then:
mkdir -p ~/.termux/boot
cat > ~/.termux/boot/start-agent <<'EOF'
#!/data/data/com.termux/files/usr/bin/sh
termux-wake-lock
cd /data/data/com.termux/files/home/nexo-rs
export CHAT_AUTH_SKIP_PERM_CHECK=1
exec ./target/release/agent --config ./config
EOF
chmod +x ~/.termux/boot/start-agent
Disabling the browser plugin
If you don't need headless browser control (most phone-hosted
agents don't), drop it from config/extensions.yaml:
extensions:
disabled: [browser]
Or, if you have tur-repo chromium installed and want nexo-rs to
spawn it, use the browser.args field to forward the flags Termux
needs:
# config/plugins/browser.yaml
browser:
headless: true
executable: /data/data/com.termux/files/usr/bin/chromium
args:
- --no-sandbox
- --disable-dev-shm-usage
- --disable-gpu
The built-in launch flags still apply; args is appended after
them so you can also override any of the built-ins (Chrome's CLI
parser uses last-wins).
Alternative: launch chromium yourself and attach via cdp_url:
# config/plugins/browser.yaml
browser:
# Start chromium yourself with:
# chromium --headless --no-sandbox --disable-dev-shm-usage \
# --disable-gpu --remote-debugging-port=9222 &
cdp_url: http://127.0.0.1:9222
When cdp_url is set, args is ignored — nexo-rs doesn't spawn
Chrome, only connects to yours.
Verify
curl localhost:8080/ready
curl localhost:9090/metrics
./target/release/agent status
Upgrading
cd ~/nexo-rs
git pull
cargo build --release
# restart under whichever method you picked (wake-lock / runit / Boot)
Android's graceful shutdown still runs on SIGTERM — closing the Termux session or killing the process drains the disk queue cleanly.
See also
- Installation — shared prerequisites
- Native install (no Docker) — the Linux/macOS path the Termux recipe is a sibling of
- Plugins — Browser
- Config — broker.yaml