ternux installs with sensible defaults, and everything can be tuned. This page explains every knob, where it lives, and why it is set the way it is.
Install-time choices
| Setting | Default | Notes |
|---|---|---|
--user NAME |
ternux |
Debian user created inside the container |
--locale LANG |
en_US.UTF-8 |
Desktop locale (see below for Bangla) |
--backend |
auto |
auto detects Adreno → zink, else virgl |
--zsh |
off | Switch the Termux shell to zsh as well |
--with-* |
none | Optional workload profiles |
To change the user or locale after installation, run the installer with the new
value without --resume, because resume skips phases already recorded as
complete: bash install.sh --user X --locale bn_BD.UTF-8 --yes. Back up first;
creating a new account does not migrate the old account’s home automatically.
Bangla locale
bash install.sh --locale bn_BD.UTF-8
This generates the bn_BD.UTF-8 locale inside Debian and installs
Noto/Symbola font coverage, so Bangla renders correctly in the desktop
terminal and apps.
Installer output
The installer’s renderer is a display choice only. Whatever the screen can show,
the complete output of every phase is appended to $TERNUX_LOG_DIR/ternux.log.
| Variable | Default | Effect |
|---|---|---|
TERNUX_UI |
auto |
auto, dashboard, plain or off — the same values as --ui |
TERNUX_NO_ANIM |
unset | 1 freezes the spinner and colour cycling; the dashboard still updates |
TERNUX_QUIET |
0 |
Suppresses shared status messages and disables the frame |
TERNUX_JSON |
0 |
Requests structured output where a command documents it; disables the frame |
TERNUX_YES |
unset | 1 accepts the documented defaults without prompting, like --yes |
TERNUX_LOG_DIR |
$TMPDIR/ternux |
Directory for ternux.log and the install stream log |
TERNUX_STATE_DIR |
~/.local/share/ternux |
Phase state, saved install choices, saved profiles |
TERNUX_COLS, TERNUX_ROWS |
unset | Force a frame geometry; intended for tests and reproducible transcripts |
Renderer selection is explained in Installation → The installer screen.
The launcher — ~/x.sh
Generated for your GPU route and syntax-checked at install time. Edit it freely; a reinstall regenerates it (your edits are replaced).
Zink (Adreno) environment
MESA_LOADER_DRIVER_OVERRIDE=zink Force Mesa's Zink Gallium driver
GALLIUM_DRIVER=zink (same intent, legacy spelling — both set)
TU_DEBUG=sysmem,noconform Turnip options for correct desktop GL
MESA_VK_WSI_DEBUG=sw Software WSI — avoids X11/Vulkan surface issues
MESA_DISK_CACHE_SINGLE_FILE=1 Shader cache as one file, faster warm starts
MESA_SHADER_CACHE_MAX_SIZE=2048M Cap so the cache can't eat all storage
MESA_SHADER_CACHE_DIR=/tmp/mesa_cache Cache in the shared tmp (RAM-backed)
QT_X11_NO_MITSHM=1 / _X11_NO_MITSHM=1 Disable MIT-SHM (broken over X11 here)
XDG_RUNTIME_DIR=~/.runtime Required by dbus/GTK apps
--bind /dev/kgsl-3d0 Expose the Adreno kernel node to the container
Why the cache tweaks? The phone’s storage is slow flash; a single-file, size-capped cache keeps app warm-starts fast without letting Mesa silently consume gigabytes.
VirGL environment
GALLIUM_DRIVER=virpipe Route GL over the VirGL pipe
MESA_GL_VERSION_OVERRIDE=4.3COMPAT Advertise OpenGL 4.3 compatibility to apps
MESA_GLES_VERSION_OVERRIDE=3.2
The host-side virgl_test_server_android process is started before the
container; the launcher warns loudly if it fails to start (otherwise the
session silently falls back to software rendering).
Audio
Three cooperating pieces:
| Where | What |
|---|---|
Termux $PREFIX/etc/pulse/default.pa |
TCP bridge module on 127.0.0.1:4713, OpenSL sink as default |
| Launcher | starts pulseaudio before the container, loads the bridge |
Debian ~/.config/pulse/client.conf |
default-server = tcp:127.0.0.1:4713 |
Why loopback-only? The bridge crosses the container boundary over TCP, so
an anonymous ACL is needed — an explicit listen=127.0.0.1 keeps it off the LAN. Other same-device clients
can still reach a loopback listener. Never change the listener to 0.0.0.0
without replacing anonymous access with deliberate authentication and firewalling.
To pick a different sink (Bluetooth, headphones), change the
set-default-sink line in default.pa and restart the session (killx,
then x).
Fonts
Installed inside Debian:
fonts-noto-color-emoji— emojifonts-symbola,fonts-font-awesome,fonts-powerline— symbol coverage- JetBrainsMono Nerd Font — terminal icon glyphs, downloaded once into
~/.local/share/fonts(sentinel file prevents re-downloads)
Add more fonts any time: drop the files in ~/.local/share/fonts and run
fc-cache -f.
State files
| Path | Purpose |
|---|---|
~/.ternux-state |
Which installer phases completed (powers --resume, --status) |
~/.ternux-state also records |
The SHA-256 of the downloaded Turnip driver |
$TMPDIR/ternux-install.log |
Full log of the last installer run |
Deleting ~/.ternux-state discards completion records. Do not use --resume
to reapply a completed phase; use the relevant ternux repair path or rerun
the installer without --resume, with a backup first.
Held Mesa packages (Zink route)
db
sudo apt-mark showhold # expect: mesa-vulkan-drivers libgl1-mesa-dri ...
These are held so a routine apt upgrade cannot replace the Turnip-backed
path with stock Mesa and silently switch you to llvmpipe. Upgrade them
deliberately:
sudo apt-mark unhold mesa-vulkan-drivers libgl1-mesa-dri libglx-mesa0 libgbm1 libegl-mesa0
sudo apt upgrade
sudo apt-mark hold mesa-vulkan-drivers libgl1-mesa-dri libglx-mesa0 libgbm1 libegl-mesa0
…then verify the renderer string again (glxinfo | grep renderer).
ternux — Copyright (c) 2026 Sobuj Miah (@soobujmiah) · Apache-2.0