You get a Linux distribution running under a chroot on the phone, install a VPN client inside it, and the shell announces a completed tunnel. Then you switch to a browser and the traffic goes out over mobile data as if nothing happened. Or the opposite: every app on the phone loses connectivity because the client installed a default route in the namespace Android is actually using. Those two symptoms come from the same missing piece, and neither one is a bug in the VPN client.

The shell says connected, the apps disagree

The first outcome is the common one. A userspace tunnel opened from a chroot can complete its handshake, print its statistics and carry traffic that the same shell generates, while Android's applications keep using the phone's default network. Nothing is intercepting them, because nothing told Android that a VPN exists.

The second outcome is the dangerous one. If the chroot shares Android's network namespace, which it does by default, a process with enough privilege can add routes and a TUN interface that affect the whole phone. Then the tunnel "works" for every app, including the ones you did not intend to route, and the phone's connectivity now depends on a daemon that has no lifecycle management, no connection indicator and no always-on policy.

Which of the two you got is answerable in one command. Compare ip route inside the chroot with the same command from an Android shell outside it. Identical output means the chroot is in the host namespace: any networking change it makes is phone-wide. Output that differs means the launcher created a namespace for it, and its tunnel is invisible to Android by construction.

What the chroot changed and what it did not

ObjectEffect of a chroot
Pathname resolutionChanged: lookups start at the new root
Kernel and driversUnchanged: the phone's kernel, its TUN driver, its limits
Network namespaceUnchanged unless the launcher creates one
Android VPN registrationUnchanged: no app consented, no VPN is selected

The chroot system call does one thing: it changes the directory used for pathname resolution. The man page is explicit that it is not a security boundary, and it says nothing about interfaces, routes or VPN state. Everything people expect from "a Linux container" — a private network stack, a filtered filesystem, resource limits — comes from other mechanisms that a launcher may or may not have used.

That is why claims about a chroot "isolating" a VPN are usually answering the wrong question. The relevant question is which namespace the process runs in and which SELinux domain it is confined to, and both are properties of how it was started, not of the word chroot.

TUN needs three things, and a device node is only one

A traditional userspace tunnel needs a TUN device it can open, kernel support for that device, and permission to configure the interface and routes. Those are separate requirements, and creating a pathname under /dev satisfies none of them by itself:

ls -l /dev/net/tun
ip tuntap add dev tun0 mode tun

On Android the kernel usually has TUN support compiled in, because the platform's own VPN service uses it, but that does not mean your process may use it. Interface configuration needs the network-administration capability, and SELinux decides whether the process may reach the device node at all. A denial looks like a permission error with no obvious cause, and the audit trail is where the answer is:

dmesg | grep avc
logcat -d | grep "avc: denied"

Root does not resolve this. SELinux constrains processes running as uid 0 exactly as it constrains others, so a chroot started from a root shell can still be denied a device it can see. Disabling enforcement to get an old installer working is a phone-wide decision with consequences far beyond the tunnel, and it is not a fix for a stale binary.

Why Android apps ignore your tunnel

Android's supported model is a VPN application that registers through the platform's VPN service, asks the user for consent once, and receives a file descriptor for its tunnel. The platform then routes traffic into that descriptor and enforces the app scope the user or administrator selected, which is why the same mechanism can be per-app, per-profile, and combined with always-on and block-without-VPN settings. The Android VPN development guide describes that handshake, and the key point is that it is a registration, not a routing trick.

A daemon inside a chroot never registers. There is no consent dialog, no key icon in the status bar, no per-app include or exclude list, and no participation in the always-on policy. Applications therefore keep using the default network, and the tunnel only carries what the shell itself sends.

Going the other way does not help either. Pushing routes into the host namespace captures everything, including traffic the platform expected to keep local, and it does so with no per-app control and no way for the user to see or revoke it. There is no middle setting where a chroot daemon routes traffic for one app only.

Binary compatibility is a separate wall

Even when the network side is interesting, the executable has its own requirements: CPU architecture, the dynamic loader, the C library, and the kernel facilities it expects. Android uses bionic rather than glibc, and an old binary built against a desktop distribution may need libraries that no longer exist on the device.

Symlinking a library filename to a newer version does not create ABI compatibility, and an archived cryptographic library from a decade-old package is not a maintained component. If the plan depends on that, the plan is to run unmaintained code with network privileges on a phone.

Prove it in the Android context and clean up after

Test what you actually care about, from the side that matters: open the specific app, reach the specific private destination, confirm which resolver answered, then disconnect the tunnel and confirm the documented behaviour. A result from a terminal inside the chroot is evidence about that terminal's execution context and nothing more.

If you changed host routes while experimenting, revert them and record what you changed. Then check whether the phone has an always-on VPN configured, because an older experiment that left a rule behind can look like a platform fault months later.

For a real remote-access requirement, use the service's supported client or an approved gateway design. The question worth asking is not whether a rooted installer can be made to run, but whether a supported implementation carries the apps you need across the boundary you intended, without leaving unowned privileged changes on the device.

Ingingo zihuye