Debian on Android

@casperdcl CC-BY-SA-3.0

September 2019, updated April 2023

There is much conflicting and outdated info online regarding setting up a Debian chroot on Android. The following should work on any Debian-supported architecture with chroot.

Tested (using a native /data/debian folder without sdcard mounting) on:

Everything from jupyter (accessible via localhost on any web browser app) to MATLAB should run.




Check to find the codename of the latest stable release. On a linux desktop:

sudo apt install debootstrap
sudo debootstrap --arch=arm64 --variant=minbase --foreign stable \

Pre-Second Stage

There are now 2 options for the “second stage”: either emulate the target (device) architecture, or actually do everything on the device.


Assuming working directory is the debian folder:

sudo apt install qemu-user-static
cp /usr/bin/qemu-aarch64-static usr/bin/
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
  chroot . /bin/bash

On device

Second Stage

Complete remaining setup:

/debootstrap/debootstrap --second-stage

Tweak and fix connectivity (particularly apt internet access):

echo "contrib non-free" >>  /etc/apt/sources.list
groupadd -g 1015 aid_sdcard_rw
groupadd -g 3001 aid_net_bt_admin
groupadd -g 3002 aid_net_bt
groupadd -g 3003 aid_inet
groupadd -g 3004 aid_inet_raw
groupadd -g 3005 aid_inet_admin
usermod -aG aid_inet _apt
usermod -g aid_inet _apt
apt update

Install some basic apps:

apt upgrade -yqq
apt install less vim rsync openssh-server bash-completion

In fact, any packages/customisation can be done at this stage, e.g.:

apt install python3-dev python3-tk wget curl git gcc g++ make cmake build-essential gnupg2

Clean up:

apt autoremove
apt clean

If on a desktop, exit the chroot, then rm usr/bin/qemu-*-static before proceeding.

If already on the device, skip the following copying step.


Compress the debian directory preserving permissions:

sudo tar -zcvf debian.tgz debian/

Copy to device:

Uncompress on device to /data/debian:

cd /data
su -c tar -zxvf /mnt/sdcard/debian.tgz


Superuser in a terminal emulator:


chroot (probably put in a shell script):

mount -o remount,exec,dev,suid /data
for f in dev dev/pts proc sys
  do mount -o bind /$f /data/debian/$f
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH \
  HOME=/root \
  chroot /data/debian /bin/bash -l

Make sure to exit and umount when done. This is easiest using a script (below).

Re-usable script

Place in e.g. /system/bin/debian and execute as su -c debian

#!/system/bin/sh -x

function mounted() {
    local m
    while read _ m _; do
        if [ x$m = x$1 ]; then
            return 0
    done </proc/mounts
    return 1

#sdcard partition ext3
#mounted /data/debian || mount -t ext3 /dev/block/mmcblk1p2 /data/debian
mount -o remount,exec,dev,suid /data

mounted /data/debian/proc || mount -t proc proc /data/debian/proc
mounted /data/debian/sys || mount -t sysfs sysfs /data/debian/sys
mounted /data/debian/dev || mount -o bind /dev /data/debian/dev
mounted /data/debian/tmp || mount -t tmpfs tmpfs /data/cache
mounted /data/debian/dev/pts || mount -t devpts devpts /data/debian/dev/pts

#sdcard storage
mounted /data/debian/mnt/sdcard || mount -o rbind /sdcard /data/debian/mnt/sdcard

for dns in `getprop net.dns1` `getprop net.dns2`; do
    echo "nameserver $dns"
done > /data/debian/etc/resolv.conf

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
TERM=linux TMPDIR=/tmp HOME=/root \
chroot /data/debian/ /bin/bash -l

# if exit != 254 (special flag), unmount
if [ $? != 254 ]; then
    while read _ m _; do
        case "$m" in
        umount "$m"
    done </proc/mounts
  for f in dev dev/pts tmp proc sys ; do
    mounted /data/debian/$f && \
    umount /data/debian/$f