Skip to content

Instantly share code, notes, and snippets.

@azilber
Created March 20, 2026 07:58
Show Gist options
  • Select an option

  • Save azilber/11e915e8e861f8aedd548086aa9a6a6f to your computer and use it in GitHub Desktop.

Select an option

Save azilber/11e915e8e861f8aedd548086aa9a6a6f to your computer and use it in GitHub Desktop.

Proxmox on Hetzner: Btrfs RAID1 with UEFI Setup guide for a Hetzner dedicated server with two drives (/dev/sda and /dev/sdb) using: ESP: mdadm RAID1 (--metadata=1.0) so UEFI firmware can boot from either drive Swap: mdadm RAID1 Root: btrfs native RAID1 with degraded mount for single-drive boot survival

  1. installimage Config Place this as /autosetup in the Hetzner Rescue System, or paste it into the installimage editor when prompted.
DRIVE1 /dev/sda
DRIVE2 /dev/sdb

# SWRAID 0 disables mdadm — btrfs handles its own RAID.
# ESP and swap are mirrored manually via mdadm post-install.
SWRAID 0

BOOTLOADER grub
HOSTNAME your-hostname

PART /boot/efi  esp    512M
PART swap       swap   4096M
PART /          btrfs  all

Note: installimage only partitions and installs onto DRIVE1 (/dev/sda) when SWRAID 0 is set. /dev/sdb is left unpartitioned and is mirrored post-install.


  1. Post-install Script Run once after the first successful boot into the installed system.
#!/bin/bash
set -euo pipefail

# 1. Replicate GPT layout from sda to sdb
sgdisk /dev/sda -R /dev/sdb
sgdisk -G /dev/sdb   # randomise sdb GUID to avoid conflicts

# 2. Create mdadm RAID1 for ESP
#    --metadata=1.0 writes the superblock at the END of the partition so
#    UEFI firmware can still detect and read the FAT32 filesystem on
#    either drive independently.
umount /boot/efi
mdadm --create --verbose \
  --level=1 \
  --raid-devices=2 \
  --metadata=1.0 \
  /dev/md/esp \
  /dev/sda1 /dev/sdb1

mkfs.vfat -F32 /dev/md/esp
mount /dev/md/esp /boot/efi
mdadm --detail --scan /dev/md/esp >> /etc/mdadm/mdadm.conf

# 3. Create mdadm RAID1 for swap
swapoff /dev/sda2
mdadm --create --verbose \
  --level=1 \
  --raid-devices=2 \
  --metadata=1.0 \
  /dev/md/swap \
  /dev/sda2 /dev/sdb2

mkswap /dev/md/swap
mdadm --detail --scan /dev/md/swap >> /etc/mdadm/mdadm.conf

# 4. Add sdb root partition to btrfs and convert to RAID1
btrfs device add /dev/sdb3 /
btrfs balance start -dconvert=raid1 -mconvert=raid1 /

# 5. Install GRUB EFI
#    --removable writes /EFI/BOOT/BOOTX64.EFI, enabling boot from either
#    drive.
#
#    IMPORTANT:
#    - Do NOT use --no-nvram. NVRAM must be updated so the server can boot.
#    - Do NOT run grub-install separately on /dev/sdb. The mdadm ESP
#      RAID1 already covers both drives.
grub-install \
  --target=x86_64-efi \
  --efi-directory=/boot/efi \
  --no-floppy \
  --removable

update-grub
update-initramfs -u -k all

btrfs filesystem show /

  1. fstab Update Script Run after the post-install script to replace the installer-generated fstab entries with the correct mdadm and btrfs UUIDs.
#!/bin/bash
set -euo pipefail

ESP_UUID=$(blkid -o value -s UUID /dev/md/esp)
SWAP_UUID=$(blkid -o value -s UUID /dev/md/swap)
BTRFS_UUID=$(blkid -o value -s UUID /dev/sda3)

# Remove installer-generated entries
sed -i '/[[:space:]]\/boot\/efi[[:space:]]/d' /etc/fstab
sed -i '/[[:space:]]swap[[:space:]]/d'        /etc/fstab
sed -i '/[[:space:]]\/[[:space:]]/d'          /etc/fstab

cat >> /etc/fstab <<EOF

# ESP (mdadm RAID1)
UUID=${ESP_UUID}   /boot/efi  vfat   umask=0077                                    0  1

# Swap (mdadm RAID1)
UUID=${SWAP_UUID}  none       swap   sw                                             0  0

# Root btrfs RAID1 — degraded allows boot with one drive missing
UUID=${BTRFS_UUID} /          btrfs  defaults,degraded,x-systemd.device-timeout=10  0  0
EOF

echo "Updated /etc/fstab:"
cat /etc/fstab

  1. RAID Layer Summary Partition Drives Device Method Reason ESP sda1 + sdb1 /dev/md/esp mdadm RAID1 --metadata=1.0 UEFI reads FAT32 from either drive Swap sda2 + sdb2 /dev/md/swap mdadm RAID1 --metadata=1.0 Swap survives single drive loss Root (/) sda3 + sdb3 btrfs native btrfs RAID1 degraded mount boots on one drive

  1. Recovery: Rescue System Procedure If the server fails to boot, activate the Hetzner Rescue System and follow these steps. Assemble arrays and mount
mdadm --assemble --scan
cat /proc/mdstat   # verify md/esp and md/swap are active

mkdir -p /mnt/root
mount -o degraded /dev/sda3 /mnt/root   # use /dev/sdb3 if sda failed
mount /dev/md/esp /mnt/root/boot/efi
mount --bind /dev  /mnt/root/dev
mount --bind /proc /mnt/root/proc
mount --bind /sys  /mnt/root/sys
mount --bind /sys/firmware/efi/efivars /mnt/root/sys/firmware/efi/efivars

chroot /mnt/root

Diagnose

# Verify GRUB EFI binary exists
ls /boot/efi/EFI/BOOT/BOOTX64.EFI

# Check fstab
cat /etc/fstab

# Check UEFI boot entries — Linux entry must appear and be first in BootOrder
efibootmgr -v

Fix: GRUB EFI binary missing

grub-install \
  --target=x86_64-efi \
  --efi-directory=/boot/efi \
  --no-floppy \
  --removable
update-grub

Fix: GRUB binary exists but no UEFI boot entry

# Adjust --loader path for your distro if needed
efibootmgr --create \
  --disk /dev/sda --part 1 \
  --label "Linux" \
  --loader '\EFI\BOOT\BOOTX64.EFI'

Fix: Wrong btrfs UUID in fstab

blkid /dev/sda3   # get correct UUID
vi /etc/fstab     # update the root UUID

Fix: initramfs missing mdadm support

update-initramfs -u -k all

Verify boot order and reboot

efibootmgr -v   # Linux entry should be first in BootOrder
exit            # exit chroot
reboot
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment