← BitPanel

Android & Termux

This is what the panel was built on — a OnePlus 6 in a drawer. It runs well here, but the installer does not: Android has no service manager, apt is Termux's own, and several dependencies have no Android build at all.

npx bitpanel install will refuse to run here, on purpose. It is apt- and systemd-shaped. The steps below are the equivalent, and they are not long.

Packages

pkg install nodejs git nginx openssh netcat-openbsd garage rclone
npm install -g pm2

Garage comes from pkg rather than the upstream release: Termux packages are compiled for bionic, and the official binary is glibc-linked and will not start.

Two Termux add-ons

Termux:Boot

Replays the pm2 dump after a reboot. Without it nothing comes back — there is no systemd here to do it.

termux-exec

Rewrites #!/usr/bin/env shebangs, which the helper scripts rely on. Termux has no /usr/bin.

Install the panel

Clone at a release tag rather than a branch, so the panel knows which version it is and can update itself later.

git clone --depth 1 --branch v0.1.7 \
  https://github.com/yashthakur1/bitroot-panel.git ~/apps/bitroot-panel
cd ~/apps/bitroot-panel
npm install --include=dev
npm run build

--include=dev matters: the build needs TypeScript, and npm drops dev dependencies whenever NODE_ENV=production is set.

Then the helper scripts, and a minimal .env:

mkdir -p ~/bin
for f in server-scripts/*; do
  head -c 2 "$f" | grep -q '^#!' && install -m 755 "$f" ~/bin/
done

printf 'PORT=3210\nSESSION_SECRET=%s\nDASHBOARD_PASSWORD=%s\n' \
  "$(openssl rand -hex 32)" "$(openssl rand -base64 18 | tr -dc 'A-Za-z0-9' | cut -c1-20)" \
  > ~/apps/bitroot-panel/.env
chmod 600 ~/apps/bitroot-panel/.env

Only scripts are copied — the loop checks for a shebang, so data files like ports.conf stay put. Overwriting that one would wipe the machine's port registry.

Start it

PORT=3210 pm2 start npm --name bitroot-panel --cwd ~/apps/bitroot-panel -- start
pm2 start garage --name garage -- server
pm2 save

PORT has to be in the environment, not just .env. next start reads the port from the process environment; a PORT line in a dotenv file alone leaves the panel on 3000 while everything else expects 3210.

pm2 save matters more here than on Linux. With no systemd, Termux:Boot replays that saved dump and nothing else will.

Open http://localhost:3210 on the phone, or reach it from another device over Tailscale. The setup wizard takes it from there.

What will bite you

ThingWhat actually happens
/dev/tcp Fails silently under sh, which is dash. Anything probing a port must use nc -z.
ss, netstat Return nothing — Android denies netlink to apps. Listening sockets cannot be enumerated; connect to them instead.
node-gyp Native modules need GYP_DEFINES="android_ndk_path=" or it will not configure.
docker The package exists but ships no daemon.
ports < 1024 Unavailable to a non-root process.
glibc binaries Fail with cannot execute: required file not found — the ELF interpreter is missing, not the file. Bun, turbo and Claude Code past 2.1.112 are all in this category.
tailscale Runs as the Android app, so there is no CLI in Termux. The panel detects the tailnet from the interface address instead, and tailscale serve cannot run here.

Keeping it alive

Android is aggressive about background processes. Acquire a wakelock and exclude Termux from battery optimisation, or the device drops off the network while it sleeps — the services stay running, but nothing can reach them.

termux-wake-lock

A phone is a real server with real limits. Its upload link is the ceiling on everything public, which is why storage leans on edge caching and compresses before it sends. None of that is hidden in the UI: a service bound to loopback says so rather than offering a link that will not open.

Updates

Because the clone is at a tag, Config → Setup knows which release is running and offers the newer one when there is one — it fetches, builds and restarts by itself. A build takes several minutes on a phone, so it runs detached and streams its log.