Edit this page
ternux documentation Updated 17 Aug 2026

Configuration

Every ternux setting explained: launcher environment variables, GPU routes, audio bridge, locale, fonts and where each file lives.

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 — emoji
  • fonts-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

Was this page useful? Report mistakes, gaps, or new device evidence.
Open an issue