HowTo: Install Devuan 3 GNU+Linux (beowulf) base system on ARM via Debootstrap

This tutorial describes a method I developed to prepare and install a Devuan 3 (beowulf) base system for the armhf architecture. I should also work for arm64 and others with small modifications. Instead of building machine-specific images, I debootstrap a single unified build that can be used across numerous ARMv7 boards without rebuilding.

Of course, the build is still architecture-specific, so if you use arm64 or another architecture instead of armhf you will need to build a separate image.

Requirements and assumptions

To apply this tutorial you will need the following:

  • ARM board supported by the Linux Kernel 4.19. This tutorial assumes you have a 32bit (armhf) board. If your board has a different architecture (e.g. arm64) it should also work with slight modifications (not covered in this tutorial). Check the dtb files shipped by default with Debian in [1] and [2] to see if your board is supported. If your board is not listed there but supported by the Linux Kernel 4.19, it should still work, but you will have to obtain and add the dtb files yourself (not covered in this tutorial).

  • working u-boot image (preferably mainline) for your device that is not ancient (ability to boot kernels directly from ext4 partitions, support for extlinux.conf)

  • working serial console attached to your ARM board

Why not use the provided images on the Devuan mirrors?

  • there are no images for beowulf yet (installing ascii and upgrading is not what I wanted)

  • the images for ascii use a hard-coded, unmaintained kernel without any working concept for security updates

  • the images for ascii are shipped with proprietary blobs and the sources.list file includes non-free sources as well.

  • the images for ascii include packages not installed in the base setup that everybody might want (e.g. screen, openssh-server)

  • the images use ext4 for the root filesystem but I prefer using f2fs in order to reduce wear of my flash media.

  • the images for ascii use the old-style u-boot configuration (boot.scr and boot.cmd) that is hard to maintain.


All data and information provided in this tutorial is for informational purposes only. The author makes no representations as to accuracy, completeness, currentness, suitability, or validity of any information on this tutorial and will not be liable for any errors, omissions, or delays in this information or any losses, injuries, or damages arising from its display or use. All information is provided on an as-is basis.

In no event, the author or this forum will be liable for any loss or damage including without limitation, indirect or consequential loss or damage, or any loss or damage whatsoever arising from loss of data or profits arising out of, or in connection with, the use of this tutorial.

Step 1: Prepare environment

I strongly recommend to use a virtual machine with a live environment for preparation because this significantly lowers the risk of data loss in case of errors (e.g. if you specify the wrong device name in some command). In principle, you can use any environment that supports Debootstrap (even Alpine Linux).

I used a Debian 10 GNU/Linux Live CD. Using a Devuan GNU+Linux Live CD would make some things simpler, however, the current ascii Live CD has a severe unpatched apt vulnerability and thus, was not considered as an viable option.

Refresh the package index and install wget:

sudo apt update
sudo apt install wget

Download the Devuan keyring (check for the latest version):


And install it:

sudo dpkg -i devuan-keyring_2017.10.03_all.deb

Install the necessary dependencies:

sudo apt install binfmt-support qemu qemu-user-static

Download devuan’s debootstrap (again, check for the latest version of it):


Install devuan’s debootstrap:

sudo dpkg -i debootstrap_1.0.114+devuan1_all.deb

Step 2: Create chroot

We will be doing the rest as root, so become root first:

sudo su -l

Create a directory for your chroot:

mkdir devuan_armhf_beowulf

Run debootstrap (might take a while):

qemu-debootstrap --arch armhf beowulf devuan_armhf_beowulf

After it finished, chroot into the environment:

chroot devuan_armhf_beowulf

Step 3: Customize chroot

Install the base locales:

apt install locales

Enable the default locale:

echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen

And generate it:


Install the generic packaged kernel for armv7 systems:

apt install linux-image-armmp-lpae

Create a directory inside /boot to hold the device tree binary (dtb) files:

mkdir -p /boot/dtbs

Create a hook script that will copy over the dtb files each time a new kernel is installed:

cat <<'EOF' >> /etc/kernel/postinst.d/copy-dtbs

set -e

echo Copying current dtb files to /boot/dtbs....
cp /usr/lib/linux-image-${version}/*.dtb /boot/dtbs/

And make it executable:

chmod +x /etc/kernel/postinst.d/copy-dtbs

Call the script once to make sure it works and to initially copy over the current dtb files (replace 4.19.0-5-armmp-lpae by the current version at the time of installation):

/etc/kernel/postinst.d/copy-dtbs 4.19.0-5-armmp-lpae

Create extlinux dir (it will hold the configuration files the u-boot bootloader will use):

mkdir -p /extlinux

Create an initial extlinux config file (can be customized in the next step):

cat <<'EOF' >> /extlinux/extlinux.conf
DEFAULT devuan

LABEL devuan
MENU LABEL Linux devuan
KERNEL /vmlinuz
INITRD /initrd.img
APPEND root=/dev/mmcblk0p1

Activate the serial console (if your target machine has a console other than ttyS0 such as AMA0 adapt it):

echo "T1:12345:respawn:/sbin/agetty -L ttyS0 115200 vt100" >> /etc/inittab

Set the root password (use some generic default password, you will want to change it later anyways):


Remove the /data directory created by apt:

rm -rf /data

Step 3b (optional): Add f2fs support

Install the f2fs tools:

apt install f2fs-tools

Add the module to /etc/initramfs-tools/modules:

echo "f2fs" >> /etc/initramfs-tools/modules
echo "crc32" >> /etc/initramfs-tools/modules

And regerate the initrd:

update-initramfs -u

Step 3c (optional): Add firmware

Depending on the devices you want to operate in your system it can be a good idea to install additional firmware. For instance, I am using ath9k-based USB devices so let’s add the open source firmware for it:

apt install firmware-ath9k-htc

Step 4: Pack

Exit the chroot:


Change to the directory of the chroot and pack it:

cd devuan_armhf_beowulf
tar cfvzp /root/beowulf_armhf.tar.gz .

Now we have a nice tar.gz archive that can be used for deploying on the target machines. Fetch this archive from your live environment and put it in a safe place.

Step 5: Partition and flash

The system as we prepared it is suitable for flashing on a (micro) sdcard that contains everything in one partition with a ext4 filesystem. This is the most simple setup but has some disadvantages.

Having a separate boot partition is good if you want to sign and verify your boot chain (kernel, initrd, dtb) later. It also helps if your device has another storage (e.g. eMMC) that is not supported by the boot-loader - you can have /boot on your sdcard and use other devices for the root filesystem and the rest.

In the following, we will cover both variants.

WARNING: Make sure to change /dev/sdX in the following examples to match the actual device name of your sdcard!

But before we get to that, I suggest you first erase your sdcard so that you are sure there are no leftovers:

dd if=/dev/zero of=/dev/sdX

Furhermore, make sure /mnt/ is not mounted by inspecting the output of the following command (ideally, it would give no output):

mount|grep /mnt

(this tutorial will assume you can use /mnt as mount point in the following)

Variant 1: Single “all-in-one” ext4 partition

Create a MBR partition table and a single ext4 partition on your sdcard:

echo "o

" | fdisk /dev/sdX

Create an ext4 filesystem:

mkfs.ext4 -m0 /dev/sdX1

Mount it:

mount /dev/sdX1 /mnt

Change there:

cd /mnt

Unpack the rootfs:

tar xzvpf /path/to/your/beowulf_armhf.tar.gz

Add an fstab entry:

cat <<'EOF' >> etc/fstab
/dev/mmcblk0p1 / ext4 errors=remount-ro 0 0

Exit, sync and unmount:

cd /
umount /mnt

Variant 2: Separate boot and root partitions

In this variant, we will use a small bootable ext4 partition to hold /boot and a bigger f2fs partition for the root filesystem on the rest of the sdcard. Create such a MBR partition table:

echo "o


" | fdisk /dev/sdX

Format the first filesystem as ext4 and the second one as f2fs:

mkfs.ext4 -m0 /dev/sdX1
mkfs.f2fs /dev/sdX2

Create directories for the mount points:

mkdir -p /tmp/mnt-boot
mkdir -p /tmp/mnt-root

Mount the filesystems:

mount /dev/sdX1 /tmp/mnt-boot
mount /dev/sdX2 /tmp/mnt-root

Extract the image to the root first:

cd /tmp/mnt-root
tar xzvpf /path/to/your/beowulf_armhf.tar.gz

Create the fstab file:

cat <<'EOF' >> etc/fstab
/dev/mmcblk0p1 /boot ext4 errors=remount-ro 0 0
/dev/mmcblk0p2 / f2fs defaults 0 0

Move contents that belong to boot contents and remove symlinks:

mv boot/* /tmp/mnt-boot/
rm -rf boot
mkdir boot
mv extlinux /tmp/mnt-boot/
rm initrd*
rm vmlinuz*

Recreate the symlinks (replace 4.19.0-5-armmp-lpae by the actual version):

cd /tmp/mnt-boot
ln -s vmlinuz-4.19.0-5-armmp-lpae vmlinuz
ln -s initrd.img-4.19.0-5-armmp-lpae initrd.img

Finally, change the entires in the extlinux configuration file:

sed -i "/DEVICETREEDIR/c\DEVICETREEDIR /dtbs" extlinux/extlinux.conf
sed -i "/APPEND/c\APPEND root=/dev/mmcblk0p2" extlinux/extlinux.conf

Exit, sync and unmount:

cd /
umount /tmp/mnt-root
umount /tmp/mnt-boot

Step 6: Flash bootloader and boot

Finally, install your bootloader. This is board-specific, e.g. for an Allwinner-A20-based Cubietruck board you would do it as follows:

dd if=/path/to/your/u-boot-sunxi-with-spl-cubietruck.bin of=/dev/sdX bs=1k seek=8

And that’s already it! Put the prepared sdcard in your device, hooks up your serial console and give it a try!

Step 7: Post-Installation

Now that you got your system booted, you probably want to do further configuration (specific for this installation) after booting:

  • change the root password
  • add additional user accounts
  • configure network
  • configure sources.list to include security-updates etc.
  • configure timezone settings
  • reconfigure locale
  • configure fstab, so filesystem is remounted read-only in case of a boot after a crash
  • install an ssh server
  • install your favorite packages

This tutorial does not cover these steps, however, I plan to create one that tackles these steps for any Debootstrap-based installations, soon.

External References

(The providers of these resources are solely responsible for them - see legal notice).

History / Changelog

  • [2019-07-15] Major rewrite, published on this site
  • [2019-04-14] Initial writeup posted in the Devuan forums


(Comment features are provided by external parties and are not monitored by me.)

Join the discussion on Mastadon (external resource)