Linux Web Hosting, DevOps, and Cloud Solutions

Installing Ubuntu 22.04 with Btrfs RAID 1 on Hetzner Dedicated Server (installimage script)






Installing Ubuntu 22.04 with Btrfs RAID 1 on Hetzner Dedicated Server (NVMe Disks)


Installing Ubuntu 22.04 with Btrfs RAID 1 on Hetzner Dedicated Server (NVMe Disks)

Objective

In this guide, I’ll walk you through installing Ubuntu 22.04 on a Hetzner dedicated server using Btrfs with RAID 1. We’ll be using Hetzner’s installimage tool with two NVMe drives. The initial provisioning will be done with software RAID disabled (SWRAID 0) — allowing Btrfs to manage the redundancy layer itself.

At the end of this process, we’ll have:

  • A running Ubuntu 22.04 system on Btrfs
  • Metadata and data converted to RAID1
  • Dual GRUB installations for boot redundancy
  • Clean separation of /boot/efi, swap, and Btrfs root.

Step 1: Boot into Rescue System

From the Hetzner Robot or Cloud Console, reboot the server into Rescue Mode and SSH into it.

Before starting the installation, make sure to clean up any existing software RAID and partitions:

mdadm --stop /dev/md/*
wipefs -fa /dev/sd* # for SATA
wipefs -fa /dev/nvme*n1   # for NVMe

Check the disk layout:

lsblk

You should see something like:

root@rescue ~ # lsblk
NAME     MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
loop0      7:0    0  3.4G  1 loop
nvme1n1  259:0    0  1.7T  0 disk
nvme0n1  259:1    0  1.7T  0 disk
root@rescue ~ #

Step 2: Prepare a Custom installimage.conf

Create a minimal config to set up EFI, swap, and a single Btrfs volume with one subvolume mounted as root (/):

cat > installimage.conf <<EOF
DRIVE1  /dev/nvme0n1
DRIVE2  /dev/nvme1n1
SWRAID  0
BOOTLOADER grub
PART /boot/efi esp 256M
PART swap swap 32G
PART btrfs.1 btrfs all
SUBVOL btrfs.1 @ /
IMAGE /root/.oldroot/nfs/images/Ubuntu-2204-jammy-amd64-base.tar.gz
HOSTNAME Ubuntu-2204-jammy-amd64-base
EOF

Ensure your SSH public key is available at /tmp/authorized_keys so you can log in post-installation.

Start installation:

installimage -c installimage.conf -K /tmp/authorized_keys

Step 3: Confirm Initial Installation

After installation, validate disk partitioning:

lsblk

You should see:

root@rescue ~ # lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
loop0         7:0    0  3.4G  1 loop
nvme0n1     259:0    0  1.7T  0 disk
├─nvme0n1p1 259:2    0  256M  0 part
├─nvme0n1p2 259:4    0   32G  0 part
└─nvme0n1p3 259:6    0  1.7T  0 part
nvme1n1     259:1    0  1.7T  0 disk

Step 4: Clone Partition Table to Second Disk

To mirror partition layout:

sfdisk -d /dev/nvme0n1 | sfdisk --force /dev/nvme1n1

Verify:

lsblk

Now both disks should be identically partitioned.

root@rescue ~ # lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
loop0         7:0    0  3.4G  1 loop
nvme0n1     259:0    0  1.7T  0 disk
├─nvme0n1p1 259:2    0  256M  0 part
├─nvme0n1p2 259:4    0   32G  0 part
└─nvme0n1p3 259:6    0  1.7T  0 part
nvme1n1     259:1    0  1.7T  0 disk
├─nvme1n1p1 259:3    0  256M  0 part
├─nvme1n1p2 259:5    0   32G  0 part
└─nvme1n1p3 259:7    0  1.7T  0 part
root@rescue ~ #

Step 5: Add Second Disk to Btrfs

Mount the root Btrfs partition:

mount /dev/nvme0n1p3 /mnt

Add the second disk:

btrfs device add /dev/nvme1n1p3 /mnt
btrfs filesystem balance /mnt

Step 6: Chroot and Install GRUB on Both Drives

Bind system directories and chroot:

for fs in proc sys dev dev/pts; do mount --bind /$fs /mnt/$fs; done
chroot /mnt
mount /boot/efi
mount -t efivarfs none /sys/firmware/efi/efivars

Check UUIDs:

blkid /dev/nvme0n1p3
blkid /dev/nvme1n1p3

Ensure /etc/fstab uses the UUID from the Btrfs volume and points to the @ subvolume.

root@Ubuntu-2204-jammy-amd64-base / # blkid /dev/nvme0n1p3
/dev/nvme0n1p3: UUID="4e6ec869-1ba4-44f8-abb7-91fd693b8a09" UUID_SUB="cf7a33d7-cddd-49d9-b62d-28e3dcef354d" BLOCK_SIZE="4096" TYPE="btrfs" PARTUUID="a2ce8444-85eb -4c81-aa9a-3f2d822d047a"
root@Ubuntu-2204-jammy-amd64-base / # blkid /dev/nvme1n1p3
/dev/nvme1n1p3: UUID="4e6ec869-1ba4-44f8-abb7-91fd693b8a09" UUID_SUB="617abcc7-faf8-43fc-8fc3-224a688433e8" BLOCK_SIZE="4096" TYPE="btrfs" PARTUUID="a2ce8444-85eb -4c81-aa9a-3f2d822d047a"
root@Ubuntu-2204-jammy-amd64-base / # cat /etc/fstab
proc /proc proc defaults 0 0
# efi-boot-partiton
UUID=B416-C1F6 /boot/efi vfat umask=0077 0 1
# /dev/nvme0n1p2
UUID=c86e8a3e-ec66-4190-b585-237568b87c7a none swap sw 0 0
# /dev/nvme0n1p3 belongs to btrfs volume 'btrfs.1'
# /dev/nvme0n1p3
UUID=4e6ec869-1ba4-44f8-abb7-91fd693b8a09 / btrfs defaults,subvol=@ 0 0

Install and update GRUB on both disks:

grub-install --target=x86_64-efi --efi-directory=/boot/efi /dev/nvme0n1
grub-install --target=x86_64-efi --efi-directory=/boot/efi /dev/nvme1n1
update-grub

Step 7: Verify GRUB Configuration

Check that GRUB entries exist:

grep menuentry /boot/grub/grub.cfg

Also confirm that UUIDs in /etc/fstab and GRUB config match the Btrfs UUID.

root@Ubuntu-2204-jammy-amd64-base ~ # cat /boot/grub/grub.cfg | grep menuentry
if [ x"${feature_menuentry_id}" = xy ]; then
  menuentry_id_option="--id"
  menuentry_id_option=""
export menuentry_id_option
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-4e6ec869-1ba4-44f8-abb7-91fd693b8a09' {
submenu 'Advanced options for Ubuntu' $menuentry_id_option 'gnulinux-advanced-4e6ec869-1ba4-44f8-abb7-91fd693b8a09' {
        menuentry 'Ubuntu, with Linux 5.15.0-131-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-131-generic-advanced-4e6ec869-1ba4-44f8-abb7-91fd693b8a09' {
        menuentry 'Ubuntu, with Linux 5.15.0-131-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-131-generic-recovery-4e6ec869-1ba4-44f8-abb7-91fd693b8a09' {
menuentry 'UEFI Firmware Settings' $menuentry_id_option 'uefi-firmware' {

root@Ubuntu-2204-jammy-amd64-base ~ # cat /etc/fstab
proc /proc proc defaults 0 0
# efi-boot-partiton
UUID=B416-C1F6 /boot/efi vfat umask=0077 0 1
# /dev/nvme0n1p2
UUID=c86e8a3e-ec66-4190-b585-237568b87c7a none swap sw 0 0
# /dev/nvme0n1p3 belongs to btrfs volume 'btrfs.1'
# /dev/nvme0n1p3
UUID=4e6ec869-1ba4-44f8-abb7-91fd693b8a09 / btrfs defaults,subvol=@ 0 0

Step 8: Reboot and SSH Login

Exit chroot and unmount all binds, then reboot:

exit
reboot

Login using your private SSH key — you added the public key during installimage.

Step 9: Convert Btrfs to RAID 1

Convert data and metadata to RAID 1:

btrfs balance start -dconvert=raid1 -mconvert=raid1 /

After completion:

btrfs filesystem df /
btrfs filesystem show /

You should now see:

Data, RAID1: ...
Metadata, RAID1: ...
root@Ubuntu-2204-jammy-amd64-base ~ #  btrfs filesystem df /
Data, RAID1: total=4.00GiB, used=2.32GiB
System, RAID1: total=32.00MiB, used=16.00KiB
Metadata, RAID1: total=2.00GiB, used=47.39MiB
GlobalReserve, single: total=5.92MiB, used=0.00B
root@Ubuntu-2204-jammy-amd64-base ~ #

✅ Final Verification

The btrfs filesystem usage / command gives an overview of the space utilization:

root@Ubuntu-2204-jammy-amd64-base ~ # btrfs filesystem usage /
Overall:
    Device size:                   3.43TiB
    Device allocated:             12.06GiB
    Device unallocated:            3.42TiB
    Device missing:                  0.00B
    Used:                          4.73GiB
    Free (estimated):              1.71TiB      (min: 1.71TiB)
    Free (statfs, df):             1.71TiB
    Data ratio:                       2.00
    Metadata ratio:                   2.00
    Global reserve:                5.92MiB      (used: 0.00B)
    Multiple profiles:                  no

Data,RAID1: Size:4.00GiB, Used:2.32GiB (57.91%)
   /dev/nvme0n1p3          4.00GiB
   /dev/nvme1n1p3          4.00GiB

Metadata,RAID1: Size:2.00GiB, Used:47.41MiB (2.31%)
   /dev/nvme0n1p3          2.00GiB
   /dev/nvme1n1p3          2.00GiB

System,RAID1: Size:32.00MiB, Used:16.00KiB (0.05%)
   /dev/nvme0n1p3         32.00MiB
   /dev/nvme1n1p3         32.00MiB

Unallocated:
   /dev/nvme0n1p3          1.71TiB
   /dev/nvme1n1p3          1.71TiB

The btrfs device stats / command shows the status of the disks, and thankfully, there are no reported input/output errors at this time:

root@Ubuntu-2204-jammy-amd64-base ~ # btrfs device stats /
[/dev/nvme0n1p3].write_io_errs    0
[/dev/nvme0n1p3].read_io_errs     0
[/dev/nvme0n1p3].flush_io_errs    0
[/dev/nvme0n1p3].corruption_errs  0
[/dev/nvme0n1p3].generation_errs  0
[/dev/nvme1n1p3].write_io_errs    0
[/dev/nvme1n1p3].read_io_errs     0
[/dev/nvme1n1p3].flush_io_errs    0
[/dev/nvme1n1p3].corruption_errs  0
[/dev/nvme1n1p3].generation_errs  0
root@Ubuntu-2204-jammy-amd64-base ~ #

root@Ubuntu-2204-jammy-amd64-base ~ # btrfs subvolume list /
ID 256 gen 147 top level 5 path @
root@Ubuntu-2204-jammy-amd64-base ~ #

Conclusion

You now have a robust Ubuntu 22.04 installation using Btrfs with RAID 1, fully bootable from either NVMe drive, and configured with GRUB on both.

This setup provides:

  • Redundancy on both bootloader and filesystem layers
  • Simple expandability for additional Btrfs devices or subvolumes
  • Clean EFI and swap layout


Exit mobile version