VMs on Mobile, without Root? Yes, Please.

Kumar Gaurav Pandey
7 min readNov 7, 2023

--

Android is a capable operating system, why not try testing its limits?

Boredom led me down a rabbit hole of discovering various tinkering projects for Android. This piqued my DevOps curiosity, prompting me to explore running containers on the platform. That curiosity, in turn, led me down another rabbit hole: running VMs on Android. There have been many twists and turns — perhaps a Docker article is warranted later. For now, let’s focus on installing VMs.

In this tutorial I will be using my Redmi Note 7, with following specifications:

(The above configuration might be slightly different because I am running custom kernel as well as custom ROM on my device)

Step 1: Setting up everything

We will be needing a terminal emulator for running VMs, here I will be using Termux, one of the most famous terminal emulator in Android world.

We will first need to update Termux to latest package:

pkg update && pkg upgrade

After this we will need some packages to be installed,

pkg install wget qemu-system-x86-64-headless qemu-utils

what are these tools we are installing here 🤔

wget: This is a free utility for non-interactive downloading of files from the web. It supports HTTP, HTTPS, and FTP protocols, as well as retrieval through HTTP proxies.

qemu-system-x86–64-headless: this refers to a version of QEMU, which is an open-source machine emulator and virtualizer, that doesn’t include a graphical user interface (GUI). It is specifically for emulating x86–64 PC systems and is useful for running virtual machines on servers or in environments where a GUI is not necessary or available.

qemu-utils: This package provides a set of tools as part of QEMU, which are used for converting and managing disk images. These utilities enable users to create, convert, compress, and modify virtual disk images used by QEMU and other virtualization software.

now since we know about our tools, let’s create a folder to manage our images, storage and scripts.

mkdir virtual_machine
cd virtual_machine/

now we will be downloading the image we want to use, I will be using alpine image for demostration purposes, because it is small and can be run on low spec devices (such as a mobile), to download alpine image we will be using wget, but where will be get link for image?

we can go here, Alpine download page

Now, here, under VIRTUAL, choose x86_64 version, but do not download it yet!!

Copy link address for x86_64

we can use this link and download the ISO file using this command:

wget <link-to-iso-file>

now we will get something like:

and filename will be something like: alpine-virt-3.18.4-x86_64.iso

We will need a disk-image to install our OS onto, run the following command to add a disk image of 10Gb (Don’t worry, it won’t actually take 10Gb of storage from our device, it is maximum capacity of disk image)

qemu-img create -f qcow2 alpine.qcow2 10G

to explain our above command, we can break it down in smaller chunks:

qemu-img: This is the command-line tool for creating, converting, and managing QEMU disk images.

create: you guessed it, to create an image

-f : to specify format of image

qcow2: it stands for "QEMU Copy On Write version 2" and is a format that allows for some advanced features like snapshotting, compression, and encryption.

alpine.qcow2: here “alpine” being name of image and “.qcow2” being extension used to qcow2 format.

10G : This specifies the size of the disk image to be created. In this case, 10G means the disk image will have a maximum capacity of 10 gigabytes.

Alright, we have everything setup for installing our VM.

Step 2: Installing Alpine

Now we will be having 2 files in our directory:

  • alpine-virt-3.18.4-x86_64.iso
  • alpine.qcow2

to start the VM installation we will be running the command:

qemu-system-x86_64 -m 512 -netdev user,id=n1,hostfwd=tcp::2222-:22 -device virtio-net,netdev=n1 -cdrom alpine-virt-3.18.4-x86_64.iso -nographic -drive file=alpine.qcow2,format=qcow2

since we already know what qemu-system-x86_64 does, I will explaining flags concerned with it:

-m 512: This option sets the amount of memory that the virtual machine will have available. In this case, the virtual machine will have 512 megabytes of RAM.

-netdev user,id=n1,hostfwd=tcp::2222-:22: This sets up user-mode networking with a net device (virtual network interface) identified as n1. It also forwards TCP connections from the host machine’s port 2222 to the virtual machine’s port 22, which is commonly used for SSH.

-device virtio-net,netdev=n1: This attaches a network device to the virtual machine using the previously defined net device n1.

-cdrom alpine-virt-3.18.4-x86_64.iso: This option tells QEMU to use the alpine-virt-3.18.4-x86_64.iso image as a virtual CD-ROM drive. This ISO file contains the installer or live system for Alpine Linux, which the VM will boot from.

-nographic: This option disables the graphical output and redirects it to the console. With this, you don’t get a windowed GUI, and instead, you interact with the virtual machine through the command line.

-drive file=alpine.qcow2,format=qcow2: This option specifies that alpine.qcow2 is the disk image file the virtual machine should use, with qcow2 as the format. This disk image acts as the virtual machine’s hard drive.

after running this command, you might be stuck on blank screen for a long time, do not worry, sit back, relax and grab a coffee (maybe?). Party is just getting started.

After a while you might get this prompt:

login with root as username and no password.

now we will get a shell like this:

Hereinafter, we will need to write some command to access internet on the VM.

mkdir -p /etc/udhcpc
echo 'RESOLV_CONF="no"' >> /etc/udhcpc/udhcpc.conf
echo -e "nameserver 8.8.8.8\nnameserver 8.8.4.4" >> /etc/resolv.conf

Now since we setup DNS on our system, we should be good to go ahead with installation of our system. run:

setup-alpine

you can just start installing it with default options, after few prompts, you will be prompted for root password, this password is important as you will need it for logging in.

You can choose your timezone using “?”

You will then prompted for NTP client you can just type none

after this you will get long list of mirrors, you can choose any one or just press enter

for this option we will be choosing yes (default is prohibit-password), because we want to login with password.

It will take few minutes to generate keys.

After this you will be prompted with which disk to use? Remember the alpine.qcow2 we created?

Choose the following options as they are in the picture (remember, you have to type it out)

when prompted for erasing the disk write “y” and press enter.

and here we gooooooooo,

our installation is complete, now we can just go ahead and execute:

poweroff
exit

this may take a while…

Step 3: Booting into VM

To boot into VM we can use the old command which we used to start the installation of the Virtual Machine, just skipping the CD Rom part, like this:

qemu-system-x86_64 -m 512 -netdev user,id=n1,hostfwd=tcp::2222-:22 -device virtio-net,netdev=n1 -nographic -drive file=alpine.qcow2,format=qcow2

You can either create an alias for it, or just create a bash script which executes it.

echo "qemu-system-x86_64 -m 512 -netdev user,id=n1,hostfwd=tcp::2222-:22 -device virtio-net,netdev=n1 -nographic -drive file=alpine.qcow2,format=qcow2" >> login_to_vm.sh
chmod +x login_to_vm.sh
./login_to_vm.sh

You will be greeted with the same login screen, now you can just use “root” as username and the password you set in step 2.

To ssh into your VM you can login using your localhost since we port-forwarded 22 port to 2222 port on our host machine.

ssh root@localhost -p 2222

and congratulations 🕺, you just installed VM on your phone!!!

--

--