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