Detailed installation walkthrough. For the concise path, see Quick start.
Prefer to run every command yourself? The command-by-command walkthrough — both GPU routes, the full launcher file — is the Manual installation page. The one-command installer below is that same page, scripted.
Requirements
| Recommended baseline | Why it matters | |
|---|---|---|
| Android | 10 or newer | Older builds lack the APIs Termux/X11 rely on |
| CPU | aarch64 (64-bit ARM) |
PRoot runs native binaries; 32-bit ARM is unsupported upstream |
| Storage | Installed: ~3–4 GB base; ~10–12 GB with --all |
Begin with additional free space for downloads, package caches, build trees, models and projects |
| RAM | 4 GB min, 6–8 GB preferred | The desktop + Android share memory; less RAM = more killing |
| Graphics | Adreno preferred; VirGL fallback otherwise | Zink/Turnip requires the Qualcomm KGSL path; VirGL compatibility varies by device/Android build |
| Apps | Termux (F-Droid/GitHub) + Termux:X11 | Keep Termux and all plugins from the same source; the Google Play line is experimental and differs from the main releases |
Check your device first (read-only, changes nothing):
uname -m # expect: aarch64
getprop ro.product.manufacturer # e.g. Qualcomm
getprop ro.product.model
getprop ro.build.version.release # e.g. 14
df -h "$HOME" # free space
ls -l /dev/kgsl-3d0 2>&1 # exists → Adreno → Zink/Turnip path
/dev/kgsl-3d0 present means the installer selects the direct Zink/Turnip
route. Missing means it selects VirGL, a compatibility path through a
host-side renderer. Verify either route with glxinfo -B; a desktop that opens
with llvmpipe is using CPU rendering, not proof of GPU acceleration.
The storage figures above are the approximate installed footprint, not the
minimum temporary headroom. Package versions and filesystem accounting vary.
For a clean run, the installer targets roughly 6 GB free for base and
14 GB free for --all, allowing downloads, caches, extraction, and builds;
the finished installation itself is approximately 3–4 GB or 10–12 GB.
Method 1 — One command (recommended)
curl -fsSL https://soobujmiah.github.io/ternux/install.sh | bash
This downloads the installer over HTTPS and runs it. Because piped standard input is not a terminal, this route runs unattended with the documented defaults. Read the output: a required-phase failure stops its dependants, while an optional/advisory failure is reported and leaves a nonzero final status.
The installer draws one persistent screen — device panel, step progress, live log window, elapsed time — and keeps it until the final status. Package output is shown as it happens rather than hidden behind a spinner, and every line is written to the log file whatever the terminal can render. See The installer screen for the renderer modes and how to override them.
The standalone loader fetches one validated source snapshot with bounded
retries, then reuses it for the bootstrap libraries, the Termux host CLI and the
Debian guest companion instead of requesting every module separately. Package
setup keeps the current apt source and never opens termux-change-repo inside
the frame; if that source is unreachable, select a mirror manually and re-run
with --resume.
curl broken after an upgrade? A partial upgrade can leave curl and openssl out of sync. Use wget — same installer, and the script repairs curl for you:
wget -qO- https://soobujmiah.github.io/ternux/install.sh | bash
Method 2 — download, review, then run
Piping curl into bash is convenient, but for a script that changes your
device it is better to review the entry point and the libraries it sources.
Clone the repository instead of inspecting only a standalone install.sh, which
would still download and source one complete repository snapshot when it starts:
pkg update -y && pkg install git -y
git clone https://github.com/soobujmiah/ternux.git
cd ternux
git log -1 --oneline # record the exact commit
(set -e; for f in install.sh uninstall.sh bin/ternux bin/ternux-guest lib/*.sh; do bash -n "$f"; done)
less install.sh lib/core.sh lib/phases.sh lib/detect.sh lib/ui.sh
# In less, use :n for the next file and q when finished.
bash install.sh
For a reproducible review, run git fetch --tags, check out a release tag, and
confirm git status --short is empty before inspection. The installed result is
intended to be the same, but this local-terminal route asks for one confirmation.
Add --yes only after review when you deliberately want no prompt. If interrupted,
use bash install.sh --resume; successful phases are skipped and the interrupted
run’s saved optional workload set is restored.
Method 3 — fully manual
For total control — or to debug the installer itself — the
Manual installation page walks through every single command:
base packages, the container, the GPU driver for both routes, the complete
~/x.sh launcher file, and verification. Methods 1 and 2 run those same
steps for you.
ternux CLI — host control and guest diagnostics
Installation makes ternux discoverable in both terminal environments, but the
two entry points deliberately have different responsibilities:
| Environment | Installed entry point | Supported role |
|---|---|---|
| Termux host | $PREFIX/bin/ternux with modules in $PREFIX/lib/ternux/ |
Full diagnostics, repair, desktop lifecycle, profiles, backends, update, and uninstall |
| Debian/Xfce guest | /usr/local/bin/ternux |
Guest-local status, info, doctor, and env without launching another PRoot session |
Use the full control plane from the Termux host terminal:
command -v ternux # $PREFIX/bin/ternux
ternux --version # ternux vX.Y.Z
ternux doctor # system diagnostics
ternux doctor --json # machine-readable diagnostics
ternux start # start the desktop
ternux stop # stop the desktop
ternux restart # restart the desktop
ternux repair # repair common problems
ternux verify # verify the installation
ternux benchmark # installation health and renderer check
ternux profile # manage the device profile
ternux backend # inspect or change the graphics backend
ternux info # system information
ternux info --json # machine-readable information
ternux logs # inspect logs
ternux state # installation state
ternux update # update the CLI
ternux uninstall # remove selected components
From an Xfce terminal inside Debian, use guest-local inspection commands:
command -v ternux # /usr/local/bin/ternux
ternux --version # ternux guest vX.Y.Z
ternux status
ternux info
ternux doctor
ternux env
The guest companion returns a usage error for host-only lifecycle commands such
as start, stop, repair, update, and uninstall, and tells you to run them
in Termux. This prevents accidental nested PRoot sessions. During installation,
ternux executes the exact installed host and guest commands and validates their
version responses; executable-file presence alone does not count as success.
The host dispatcher recognizes global flags, but not every command implements a JSON schema. Use structured output only for commands documented in the CLI reference.
What the installer does (and why, phase by phase)
The installer runs as 11 verified phases. Each phase checks its own work before the next one starts — a failed phase stops the install with a clear message instead of producing a half-broken desktop.
| # | Phase | What it does | Why |
|---|---|---|---|
| 1 | Preflight | Checks Termux, architecture, Android version, storage, network | Fail here and you waste no downloads; every later phase depends on these facts |
| 2 | Base packages | Installs x11-repo, termux-x11, pulseaudio, proot-distro, virglrenderer-android, tools; requests storage permission |
These are the host-side services the container needs: display, sound, and the container engine |
| 3 | Host CLI installation | Installs $PREFIX/bin/ternux plus modules in $PREFIX/lib/ternux/, then executes its exact path and checks its version |
A file can exist while its libraries are missing; successful execution is the real host-side check |
| 4 | Debian + Xfce4 | Installs the Debian rootfs and desktop packages, creates your user with passwordless sudo, installs /usr/local/bin/ternux, and executes the guest companion |
The desktop gets safe local diagnostics without nesting PRoot; sudo and the guest command are both validated |
| 5 | GPU driver | Adreno: resolves the current Debian ARM64 Turnip asset, rejects unsafe paths, validates the two target members as regular files, records URL/SHA-256, and installs only those members. Other: confirms the VirGL host renderer | Target-only extraction avoids executing archive layout assumptions. Pinning paired Mesa packages reduces the chance of a routine upgrade replacing the tested path |
| 6 | Audio, locale, fonts | Bridges PulseAudio loopback-only, generates your locale, installs emoji/powerline/Nerd fonts | Sound crosses the container boundary over TCP — loopback only. Fonts avoid tofu boxes in the terminal |
| 7 | Launcher | Writes ~/x.sh tuned to your GPU route, syntax-checks it |
One command (x) must reliably start audio → display → desktop in the right order |
| 8 | Shortcuts | Installs x, killx, db, droot, xgo, sysmon, clean-mesa for the selected Debian user |
Sets up quick shortcuts so everyday operations need only a single command |
| 9 | Optional extras | Dev tools, llama.cpp, network tools, media tools, Blender — only what you asked for | Keep the base install lean; each profile has different storage/thermal costs |
| 10 | Android safeguard check | Reads the Android child-process setting when available and prints version-aware guidance | Signal 9 can also come from memory pressure or OEM battery policy; collect evidence before changing a system-wide safeguard |
| 11 | Verification | Confirms every critical binary, file and permission actually landed | Confirms the environment is runnable — apt completing without errors does not guarantee the desktop will launch |
Installer options
bash install.sh # local terminal — one confirmation before changes
bash install.sh --yes # accept all defaults, no questions
bash install.sh --user soobuj # Debian user name (default: ternux)
bash install.sh --locale bn_BD.UTF-8
bash install.sh --backend zink # force Zink/Turnip (Adreno only)
bash install.sh --backend virgl # force the compatibility fallback
bash install.sh --zsh # also switch the Termux shell to zsh
bash install.sh --with-dev # Git, Node.js, Python, build tools
bash install.sh --with-llm # llama.cpp + Vulkan (local AI)
bash install.sh --with-network # nmap, tmux (authorised testing only)
bash install.sh --with-media # ffmpeg, GIMP, Audacity, ImageMagick
bash install.sh --with-blender # Blender (lightweight scenes)
bash install.sh --all # every optional profile
bash install.sh --resume # continue after an interruption
bash install.sh --version # show version
bash install.sh --help # show help
After installation, use the ternux CLI for diagnostics and management:
ternux doctor # diagnose
ternux repair # diagnose and fix
ternux state # what is done, what is pending
ternux uninstall # interactive removal
ternux update # self-update the CLI
Choosing a GPU backend
| Your GPU | Backend | Expectation |
|---|---|---|
| Qualcomm Adreno | auto → zink |
Measured route on the supplied Adreno setup: OpenGL → Zink → Vulkan → Turnip; verify your renderer and workload |
| Mali / Xclipse / PowerVR / other | auto → virgl |
Compatibility route via the host renderer; device support and speed vary |
| Adreno, but the driver route fails | --backend virgl |
Alternate path to test; verify that it does not fall back to llvmpipe |
Forcing zink on a device without /dev/kgsl-3d0 fails loudly at the GPU phase
before the launcher is created, rather than producing a silently-software
desktop. That failure is intentional.
The installer screen
One screen serves the whole run. The log window holds the live tail of the current phase; the complete stream is always appended to the log file.
+=========================================================+
| ternux v1.4.0 - ONE-CLICK INSTALLER |
| by Sobuj Miah - base ~3-4 GB - complete ~10-12 GB |
+=========================================================+
| Device Redmi Turbo 4 Pro - Android 15 (SDK 35) |
| Graphics Adreno 825 - backend zink - Vulkan 1.4 |
| Memory 12 GB RAM - 84 GB free - aarch64 |
| STEPS 4/11 ######------------ Debian container |
+=========================================================+
| Get:14 http://deb.debian.org bookworm/main arm64 |
| Unpacking xfce4-session (4.18.3-1) ... |
| ... +201 more lines (full log: ternux.log) |
| [ OK ] Base packages installed |
+=========================================================+
| (c) 2026 Sobuj Miah - github.com/soobujmiah 03:12 / |
+=========================================================+
| Region | What it reports |
|---|---|
| Device panel | Model, Android release and SDK, GPU, selected backend, Vulkan, RAM, free storage, architecture |
| Step bar | Phase number, total phases, and the title of the running phase |
| Log window | Live tail of the running phase, coloured by severity |
| Footer | Elapsed time and a spinner that keeps moving while a phase is quiet |
Renderer modes
| Mode | Chosen when | Behaviour |
|---|---|---|
dashboard |
Interactive terminal with colour, at least 39 usable columns and 13 rows | The persistent screen shown above |
plain |
Everything else: pipes, curl \| bash without a TTY, TERM=dumb, NO_COLOR, a very small window |
Framed lines appended in order, no cursor control |
off |
--ui off, --quiet, or --json |
Raw command output with no framing |
Selection is automatic; override it when you prefer a different result:
bash install.sh --plain # scrolling log, no full-screen dashboard
bash install.sh --no-anim # dashboard without spinner or colour cycling
TERNUX_UI=off bash install.sh # raw output, e.g. to capture a transcript
Reading the log window
- Carriage-return progress from apt, dpkg, proot-distro and curl updates a single row in place instead of scrolling the window away.
- When a phase prints faster than the screen can be read, the newest lines are
kept and the count of the rest is stated as
... +201 more lines. Errors, warnings and phase markers are never summarised. - Changing font size, rotating the device, or opening the on-screen keyboard re-fits the frame once and redraws the visible log.
Ctrl-Crestores the terminal and preserves recorded state, sobash install.sh --resumecontinues from the last completed phase.
The renderer never decides what is recorded:
ternux logs tail # follow the live install log
ternux logs show # read the whole log
ternux logs list # log files and sizes
After the install
1. Open Termux:X11 once and leave it running.
2. source ~/.bashrc
3. x ← starts the desktop
Run a full diagnostic:
ternux doctor
ternux doctor --json # machine-readable output
Then verify the graphics path from a desktop terminal:
glxinfo | grep "renderer string"
vulkaninfo --summary | grep -i driverName # Adreno: expect "Turnip"
Back up the working state before adding large models or experimental packages:
proot-distro backup debian --output ~/debian-backup.tar.gz
Updating
- The ternux CLI:
ternux updatefetches the latest version from GitHub. - An interrupted installer run: re-download the same reviewed script and use
--resume; it skips only successfully recorded phases. This does not update or repair phases already complete—useternux updatefor the CLI andternux repairfor managed artifacts. Back up before driver or distribution changes. - Debian packages:
sudo apt update && sudo apt upgradeinside the desktop. Mesa packages are held (apt-mark hold) on the Zink route on purpose — upgrading them can silently switch you back to software rendering. Unhold deliberately, not accidentally:sudo apt-mark unhold mesa-vulkan-drivers libgl1-mesa-dri libglx-mesa0 libgbm1 libegl-mesa0.
Uninstalling
ternux uninstall # preferred — interactive removal
# or
curl -fsSL https://soobujmiah.github.io/ternux/uninstall.sh | bash
# or
bash install.sh --uninstall
all means the four scoped targets shown by the command: stop the session,
remove ~/x.sh and ternux alias blocks, remove ternux state/logs, and delete the
Debian container. It does not uninstall Termux packages, remove the installed
ternux CLI/libraries, revoke shared-storage access, restore repository/mirror
choices, or revert the loopback PulseAudio line in Termux’s default.pa; those
may predate ternux and are deliberately left alone. Android files outside
Termux storage are never deleted. Clearing Termux app data is the separate
nuclear option that removes the remaining Termux installation too.
Troubleshooting
Desktop won’t start? Renderer says llvmpipe? No audio?
See Troubleshooting — every symptom maps to a cause
and a fix.
ternux — Copyright (c) 2026 Sobuj Miah (@soobujmiah) · Apache-2.0