Skip to content
Chroot to any Linux (to test it)

Chroot to any Linux (to test it)

Published: at 01:37 PMSuggest Changes

In a previous article, I talked about what’s a (minimal) Linux and explained how to launch such a system with only a compiled kernel, an initramfs and BusyBox to get some tools. You should now understand that a Linux based system needs a filesystem to be working and useful.

Rules are defined in the Filesystem Hierarchy Standard (FHS). That’s what initramfs and BusyBox provided in a very basic way. But a Linux distribution brings more: lots of tools, libraries, config files, etc. Except from its prebuilt kernel, it’s what makes it different from another.

Thus, you can test any distribution on your local machine, without installing it, without any virtualization stack. You just need to get its file system and use it with your own kernel. There is a tool for that: chroot. It’s a command included since the 7th Edition of Unix (1979).

I am chroot

You don’t trust it’s so simple? Let’s try it with Alpine Linux. It’s a very lightweight distribution, based on musl libc and BusyBox, distributed in many ways, including a tarball containing its file system.

Download it and extract it:

wget https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/x86_64/alpine-minirootfs-3.19.1-x86_64.tar.gz
mkdir alpine
tar xPf alpine-minirootfs-3.19.1-x86_64.tar.gz -C alpine

Then, you just need to chroot into it, launching sh shell as Bash is not included in Alpine by default:

sudo chroot alpine /bin/sh

To see you’re in a different environment, check /etc/os-release:

cat /etc/os-release

You should see something like:

NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.19.1
PRETTY_NAME="Alpine Linux v3.19"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"

What happens here is that chroot changes the root (/) directory of the current process to the alpine/ folder. Thus, you see it as if you booted on an Alpine Linux system, after the init and login.

You’re still on your host system, with your kernel, your processes, etc. But no local network, Internet access, devices access, or whatever.

To enable them, exit and mount some directories from your host system to the chroot environment (with --bind when we need to reflect the original). To get Internet, you’ll also need a proper DNS resolv.conf file:

sudo mount --bind /dev alpine/dev
sudo mount -t devpts /dev/pts alpine/dev/pts
sudo mount -t proc /proc alpine/proc
sudo mount -t sysfs /sys alpine/sys
cp /etc/resolv.conf alpine/etc/resolv.conf

Then, you can chroot again and install some packages, like neofetch:

sudo chroot alpine /bin/sh
apk update
apk add neofetch
neofetch

It should show some information about the system like the distribution (ASCII) logo, kernel version, CPU, memory, screen resolution, uptime, etc.

After exiting the chroot environment, you should umount the directories in the reverse order of the mount command:

exit
sudo umount alpine/{sys,proc,dev/pts,dev}

Chroot to any Linux

How to do that with any Linux distribution? For many of them, you can’t just download an archive and chroot into it. You need to get the filesystem from somewhere else. One easy way is to use the Docker registry, extract content from an image and chroot into it. There is a tool for that: docker export.

Once Docker is installed (or Podman with an alias), let’s try with Arch Linux:

mkdir arch
docker create --name arch archlinux
docker export arch | tar x -C arch

Then, you can chroot into it:

sudo mount --bind /dev arch/dev
sudo mount -t devpts /dev/pts arch/dev/pts
sudo mount -t proc /proc arch/proc
sudo mount -t sysfs /sys arch/sys
cp /etc/resolv.conf arch/etc/resolv.conf
sudo chroot arch

Then, you can update system and install some packages, like neofetch:

pacman -Syu
pacman -S neofetch
neofetch

You can do the same with any other distribution, like Debian, Fedora, NixOS, Ubuntu, etc. You can also use any Linux based container image.

But never forget: you’re still on your host system, with your kernel. It’s just a different environment, with its own file system, tools, libraries, etc. If you use tools like ps -a or top, you’ll see host processes.

A script to play with this easily

To make it easier, I wrote a script to chroot into any Linux distribution, using Docker images. It’s available on GitHub. For example, chroot into a system with nginx installed and launch it (port 80 by default).

The script downloads the Docker image, extract the filesystem, mount directories, and chroot. When you exit, it will automatically umount the directories and remove the Docker container and the extracted content.

git clone https://github.com/davlgd/chroot-from-image
cd chroot-from-image

# Use the script with the following syntax: ./chroot_from_image <image> <command>
# After launch of nginx, you'll exit the chroot environment, refuse to clean it
./chroot_from_image nginx nginx

Then, you can check that nginx is running, accessing it from the host system:

curl localhost # It works from host system, too!

To stop nginx, kill its processes and use the clean_image script to unmount, remove the Docker container and the extracted content:

kill $(pidof nginx)
./clean_image nginx

Previous Post
How to create a CLI in V
Next Post
What's a (minimal) Linux?