Self-hosted service
termux/termux-docker avatar
termux/termux-docker

termux-docker packages a Termux environment as a container image

Termux environment packaged as Docker image.

745 stars112 forksShellLicense varies

At a glance

What is it?
termux-docker is a Docker or Podman image that gives you a Termux environment, including the apt based package manager, without an Android device, with images built for five CPU architectures. It is not a Termux replacement on a phone, it is the Termux userspace lifted into a container, and it carries a documented list of caveats.
Who is it for?
termux-docker suits a developer who wants to reproduce or debug a Termux environment on a Linux machine, for example to reproduce a package build failure or to script against Termux tooling, since the image carries the same apt based package manager and root filesystem layout.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 38 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the image is, and what it deliberately leaves out

termux-docker packages a Termux environment into a Docker image, and the README states the limitation that defines the project: the environment doesn't have Android runtime components, so certain things will not be available, with DalvikVM and OpenSLES given as examples.

That sentence is the whole scope. This is not an Android emulator and not a container that pretends to be a phone. It is the Termux userspace, the prefix layout, the package manager and the command line tools, packaged so that they can run on a Linux host.

The Dockerfile shows what the image is actually made of. The build starts FROM scratch as a bootstrap stage and copies in a generated rootfs that contains termux bootstrap, aosp-libs with the bionic libc, linker, boringssl, zlib, libicuuc and debuggerd, aosp-utils with toybox, grep, mksh and iputils, and libandroid-stub. In other words, the libc is Android's bionic rather than glibc, which is the whole reason the image exists: you get the same libc the phone uses, without the phone.

The Dockerfile also handles a detail that only matters on a real device but is reproduced here deliberately. The path /data and /data/data are chowned to root and given mode 771, so that the unprivileged user has no read access to them, just like on real Android devices. The comment explains that this reproduces a class of bugs for debugging and development, and is honest about the limit: it will not reproduce bugs that require the root filesystem to be inaccessible, because it is not possible to set chmod 771 persistently on / within Docker since it reverts to 755 as soon as the container runs.

The primary language of the repository is Shell, the topics are docker, environment, linux and termux, and the last push was on 2026-09-15 with no GitHub releases.

Running it, and the architecture tags

The basic usage is one command, and it starts an interactive login shell that looks like a normal Termux installation.

sh
docker run -it termux/termux-docker

The architecture handling is simple and worth reading. When using no tag, or the tag latest, the container will automatically match the device architecture. Other architectures are available as explicit tags, and the list is aarch64, arm, i686, x86_64 and latest as the multiplatform tag.

That matters because the interesting use case is running an ARM Termux environment on an x86 machine, which is exactly what CI systems and build farms need.

The package manager is a separate image. The other package manager for Termux, pacman, is available in a separate image:

sh
docker run -it termux/termux-docker-pacman

The requirements section is short. You should have a properly configured and running Docker or Podman container system, and the README notes that further instructions give examples only for Docker even though the image works under Podman.

For non-interactive work, commands can simply be appended to the docker command line:

sh
docker run -it --rm termux/termux-docker bash -c "apt update && apt install -yq clang"

That is the shape most CI usage takes, and it uses apt with the -yq flags to avoid a prompt in a non-tty context.

Cross-architecture runs and the personality() problem

Running an AArch64 container on an x86(64) host needs a QEMU emulator registered through binfmt_misc, and the README says this can be done by one command:

sh
docker run --rm --privileged aptman/qus -s -- -p aarch64 arm

The --privileged flag on that helper is required for it to install the binfmt handler, but the container you actually run afterwards does not have to be privileged.

The README is careful to distinguish the two. AArch64 and ARM containers, and in certain rare situations some x86 containers, sometimes work properly only in privileged mode, even on some real ARM devices. If you want your containers to have standard privileges, a custom seccomp profile or a custom build of Docker might be required.

Two variants are given. The privileged container:

sh
docker run -it --privileged termux/termux-docker:aarch64

and the seccomp unconfined variant:

sh
docker run -it --security-opt seccomp:unconfined termux/termux-docker:aarch64

The third option is a custom build of Docker with the bundled patch, custom-docker-with-unrestricted-personality.patch, applied to the docker.io package. The documented sequence is to install the build dependencies, fetch the source, copy the patch into the Debian patches directory, append it to the series file, build the package with debuild, remove the golang source directories, install the resulting package and run the image. The comment on the patch notes that it limits the customizations to purely what is necessary for the personality() system call, leaving the security settings of all other system calls untouched.

The maintenance warning attached to that path is the part most people skim. You might then want to temporarily use sudo apt-mark hold docker.io to ensure the package is not automatically upgraded, causing termux-docker to stop working on the device in the future, but not upgrading can be a security risk. If using the patch, it is recommended to patch and recompile the Docker daemon after every upgrade.

Root shell, and the two entrypoints

By default the root shell is disabled in the container, because Termux doesn't really support usage of a package manager under the root account. Where you genuinely need a root shell, the entrypoint is overridden.

The provided images have two entry points: /entrypoint.sh, which is the standard one and drops privileges to the system user, and /entrypoint_root.sh, the alternate entrypoint that does not drop privileges.

sh
docker run -it --entrypoint /entrypoint_root.sh termux/termux-docker

That design is worth understanding on its own terms. The standard entrypoint dropping to the system user is not a hardening flourish, it is a mirror of how Termux itself runs, where the app's user owns the prefix. The Dockerfile reflects the same choice: the copied rootfs is owned by the system user, 1000:1000, except for /data and /data/data, and the build switches to USER 1000:1000 before running the package manager setup step.

So the default container behaves like a Termux session on a phone, and the root variant is an escape hatch for the cases where the package manager or a file permission requires it. If you are debugging a permission problem, knowing which entrypoint you are on saves a lot of confusion, because the two behave differently on every path in the prefix.

Building the images yourself

The image is generated rather than hand maintained, and the generation is a shell script.

sh
./generate.sh

Podman is a flag rather than a second script:

sh
./generate.sh --podman

And the pacman flavour is selected by an environment variable rather than a flag, which is consistent with how the Dockerfile reads its other inputs:

sh
export TERMUX_PACKAGE_MANAGER=pacman
./generate.sh

The repository layout is small and matches that: a Dockerfile, entrypoint.sh, entrypoint_root.sh, generate.sh, the custom Docker patch, and the README. The Dockerfile itself takes its inputs as build arguments, TERMUX_DOCKER__ROOTFS for the generated rootfs, TERMUX__PREFIX and TERMUX__CACHE_DIR, and the bootstrap stage is FROM scratch, so the image contains only what the generated rootfs and the later stages put there.

The second stage of the Dockerfile is where the package manager setup happens, and it branches on the same environment variable: it runs the termux-setup-package-manager script, and if the package manager is apt it runs apt update and apt upgrade with the Dpkg::Options force-confnew setting, with an equivalent branch for the other package manager. That means an image built at release time can be brought up to date inside the container without rebuilding it.

The known issues, stated plainly

The README closes with a section that says there are a number of known issues which may not be resolved, and listing them is the most useful thing in the document for an adopter.

The first is the one described above. ARM containers, and in certain rare situations some x86 containers, might require a custom seccomp profile or custom build of Docker to remove restrictions from the personality() system call. The system call is what an emulated process uses to set its execution domain, so a container running under QEMU that cannot make that call fails in ways that look like a broken image rather than a missing capability.

The second is more specific. When running certain multi threaded program in 32bit containers, the PIDs can balloon and easily exceed libc's limit, and the only way to fix this is to set /proc/sys/kernel/pid_max to 65535. The README links termux-docker issue 40 for the details.

That second one is a host-level change rather than an image change, which is worth flagging because it means the image is not entirely self-contained. A 32 bit container that spawns many threads will hit the host's process limit, and the fix touches a kernel setting on the host, not a setting inside the container.

The project is the Termux organisation's own repository, and there are no GitHub releases for the images, so the tags are published to the container registry rather than to a release page. The licence is not stated in the repository metadata, which is a small but real gap for anyone who intends to redistribute the image.

Editorial conclusion

termux-docker suits a developer who wants to reproduce or debug a Termux environment on a Linux machine, for example to reproduce a package build failure or to script against Termux tooling, since the image carries the same apt based package manager and root filesystem layout. It is the wrong tool if you need an Android runtime, because the environment has no Android runtime components and things like DalvikVM and OpenSLES are absent, and it is the wrong tool if you need a normal Debian userland, because the whole point is the Termux prefix layout. Before running it on a host that differs from the target architecture, set up the QEMU binfmt_misc handler, and read the known issues section, because the personality() call restriction and the 32 bit PID limit both bite in ways the README describes precisely.

Frequently asked questions

How do I start a Termux environment with termux-docker?

Run docker run -it termux/termux-docker with a properly configured and running Docker or Podman. This starts an interactive login shell that looks like a normal Termux installation, and with no tag or the tag latest the container matches the device architecture.

How do I run an ARM Termux container on an x86 host?

Register the QEMU emulator through binfmt_misc with docker run --rm --privileged aptman/qus -s -- -p aarch64 arm, then run the image with the aarch64 tag. The README notes that ARM containers may need privileged mode, a custom seccomp profile, or a custom build of Docker to remove restrictions from the personality() system call.

How do I get a root shell in termux-docker?

Override the entrypoint with docker run -it --entrypoint /entrypoint_root.sh termux/termux-docker. The default entrypoint /entrypoint.sh drops privileges to the system user, because Termux does not really support using the package manager under the root account.

What is missing from the termux-docker image compared with a real device?

The environment has no Android runtime components, so things such as DalvikVM and OpenSLES are not available. The image carries the Termux rootfs with bionic libc, toybox, mksh, grep and iputils, and the /data and /data/data permissions are reproduced to match a real device.

How do I build the termux-docker image myself?

Run ./generate.sh in the repository, use ./generate.sh --podman for a Podman build, and set TERMUX_PACKAGE_MANAGER=pacman before running it to build the pacman flavour. The Dockerfile takes the generated rootfs through the TERMUX_DOCKER__ROOTFS build argument.

Official sources

  1. Issues
  2. README
  3. termux/termux-docker on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/termux-termux-docker.svg)](https://hysenlabs.com/projects/termux-termux-docker)

Was this useful?