How to install Ubuntu on your Android phone

Update (May 2014): I’ve since had the occasion to do this again on my , and this time I used Linux Deploy to install 14.04 inside 4.0.x – it worked flawlessly, and besides having the source available, it has up-to-date presets to download and install the required bootstrap files directly on the phone (no computer required).

To make a long story short, we took a mini-break out in the countryside, and I got bored.

I was supposed to relax and read up on a whole bunch of stuff related to natural language processing, but since I’ve been fiddling around with LXC and chroot so often these days I decided to have a go at upgrading my phone (aka my pocket server) to 13.04.

(In case you missed that post, I’m using the Complete Linux Installer to off an old Xperia Arc S, and it works well enough for me to run an instance of this site there – and much more besides.)

do-release-upgrade worked fine to step up to 12.10 from 12.04, but the Complete Linux Installer’s supplied images are built with armel binaries whereas 13.04 has moved on to armhf exclusively – so after confirming that my Xperia could run armhf binaries via multiarch (which, incidentally, made things a tad snappier), I decided to build a new image from scratch.

Regretfully there’s very little info out there on how to go about doing that other than a few scattered forum posts, so I decided to document the process. It’s all fairly straightforward provided you’re using the Complete Linux Installer app already and have a box handy (I daresay it can be done on the phone itself on simpler cases).

First off, and for the more general case where you’ll be using an Intel machine to get this going, you need to set up QEMU and ARM binary support as well as debootstrap:

sudo apt-get install debootstrap qemu-user-static qemu-system git \
gcc-arm-linux-gnueabihf binfmt-support

Now create the filesystem itself (this is for a 2GB image) and mount it under /mnt. Since we don’t need all the bells and whistles of ext3/ext4 (after all, the end result will be running inside a file), we’ll be building everything inside an ext2 filesystem:

dd if=/dev/zero of=ubuntu.img bs=1024 count=2097152
mkfs.ext2 ubuntu-armhf.ext2.img
sudo mount -o loop ubuntu-armhf.ext2.img /mnt

Next up, use debootstrap to deploy the basics (note the arch and raring settings):

HOSTNAME=ubuntu-armhf sudo debootstrap --variant=minbase --foreign \
--arch armhf raring /mnt

Now deploy qemu-arm-static inside the soon-to-be chroot:

sudo cp /usr/bin/qemu-arm-static /mnt/usr/bin/

…and use it to finish the deployment:

LANG=C sudo chroot mnt /usr/bin/qemu-arm-static -cpu cortex-a9 /bin/bash
./debootstrap/debootstrap --second-stage

Once that’s done, we need to set up apt sources (you can optionally set up deb-src as well, but I have yet to need it):

echo "deb http://ports.ubuntu.com raring main restricted universe" > /etc/apt/sources.list
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 428D7C01

From then on, you can install stuff as required (this is my base setup):

apt-get update
apt-get install sudo apt-utils dialog less wget vim net-tools openssh-server \
htop tmux build-essential libevent-dev python-dev python-setuptools \
python-lxml sqlite3 nodejs npm golang git-core

If you have enough horsepower, you can also install a server (and a minimal X11 setup) by doing:

apt-get install --no-install-recommends tightvncserver

Even though this is not really necessary for an Android chroot, you should also set up a serial console in case you ever need to run this under QEMU again1:

cp /etc/init/tty1.conf /etc/init/ttyAMA0.conf
sed -i "s/tty1/ttyAMA0/" /etc/init/ttyAMA0.conf

To top everything off, you need to set up a user with sudo access1:

adduser ubuntu
usermod -aG sudo ubuntu

Next up, exit the chroot:

exit

Now for the Complete Linux Installer tweak, which boils down to copying across their init.sh script (of which I’ve made a local copy) to /root/init.sh and making sure it’s executable3, as well as adding a couple of extra mount points:

sudo cp init.sh /mnt/root/init.sh 
sudo chmod +x /mnt/root/init.sh
sudo rm /mnt/usr/bin/qemu-arm-static
sudo mkdir /mnt/sdcard
sudo mkdir /dev/shm
sudo umount /mnt

Now copy the image across (it should clock in at about 400MB compressed, in case you want to keep a copy around), replace the original image on your SD card, and you’re golden.

I’ve since managed to get Postgres running on mine – just disable TCP and use UNIX sockets instead so that it doesn’t get confused with the network setup.


  1. This is actually more common than you’d think - I used to run an emulated Intel chroot inside a PowerPC , and forgot to do this every time I upgraded it. ↩︎↩︎

  2. Note that the Complete Linux Installer script insists on adding the user to the admin group, which doesn’t actually exist on ↩︎

  3. I’ve tweaked the one I’m actually using a bit further, since I need /dev/shm to work. Also, I wish they’d document the configuration files somewhere – I’d also like to have custom mounts working without hacking them into the script. ↩︎

This page is referenced in: