From b098c94e19e4d0e424b0d1007faddeee12fe2c63 Mon Sep 17 00:00:00 2001 From: Fabrice Quenneville Date: Sun, 17 May 2026 04:47:26 -0400 Subject: [PATCH] feat: add redundant root with EFI mirror setup guide Covers disk formatting, BTRFS RAID1 conversion, fstab configuration, and the update-efi-mirror script with apt post-install hook setup. Includes a separate procedure for migrating to a new disk. --- README.md | 3 + notes/update-efi-mirror.md | 334 +++++++++++++++++++++++++++++++++++++ 2 files changed, 337 insertions(+) create mode 100644 notes/update-efi-mirror.md diff --git a/README.md b/README.md index 6a7b354..f2bbfb3 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ This repository is structured into several key directories: - `scripts/library/`: Libraries used by Python scripts. - `venv_utils.py`: Utility functions for creating, activating, and managing Python virtual environments. - `change_case.py`: A script for renaming files and directories by changing their case. + - `update-efi-mirror.sh`: Script for syncing a two drive EFI mirror. - `video_autoreduce.py`: A script for automatic resolution reduction of video files. - `video_autoreduce_rename.py`: A script for automated renaming of video files post resolution reduction. - `video_manage_audio.py`: A script for removing audio from video files. @@ -27,6 +28,7 @@ This repository is structured into several key directories: - `pip-packaging.md`: Packaging and publishing Python projects with pip. - `ssh.md`: SSH configuration, key management, and tunneling tips. - `storage.md`: Storage tooling — smartctl, badblocks, dd, hdparm, fdisk, and fstab/mount management. + - `update-efi-mirror.md`: Redundant root with EFI mirror setup guide. - `wordpress.md`: WordPress debugging and tips. - **pages/other/**: Templates for other pages, such as the homepage of my Debian package repository. These are provided as inspiration and should not be used as-is. @@ -40,6 +42,7 @@ This repository is structured into several key directories: - **setups/**: A collection of markdown files containing notes on configuring servers, including: - `debian_setup_aptly.md`: Comprehensive guide for installing Aptly on Debian. + - `debian_setup_dolibarr.md`: Comprehensive guide for installing Dolibarr on Debian. - `debian_setup_gitea.md`: Comprehensive guide for installing Gitea on Debian. ## 📖 Documentation diff --git a/notes/update-efi-mirror.md b/notes/update-efi-mirror.md new file mode 100644 index 0000000..c43c735 --- /dev/null +++ b/notes/update-efi-mirror.md @@ -0,0 +1,334 @@ +# Redundant Root with EFI Mirror + +## Table of Contents + +- [Redundant Root with EFI Mirror](#redundant-root-with-efi-mirror) + - [Table of Contents](#table-of-contents) + - [Overview](#overview) + - [Placeholders](#placeholders) + - [How It Works](#how-it-works) + - [Paths](#paths) + - [Setup Procedure](#setup-procedure) + - [1. Format the Disks](#1-format-the-disks) + - [2. Convert the Root Filesystem to BTRFS RAID1](#2-convert-the-root-filesystem-to-btrfs-raid1) + - [3. Configure fstab](#3-configure-fstab) + - [4. Install the Sync Script](#4-install-the-sync-script) + - [5. Configure apt to Run the Script Post-Install](#5-configure-apt-to-run-the-script-post-install) + - [6. Test](#6-test) + - [Moving to a New Disk](#moving-to-a-new-disk) + +## Overview + +This setup provides a redundant Debian root drive using BTRFS RAID1 across two disks, with a synced EFI partition on both so the machine can boot from either. The script `update-efi-mirror` keeps the backup EFI in sync and re-installs GRUB on both physical disks. It is triggered automatically after every `apt` operation. + +## Placeholders + +Replace the placeholders below with the appropriate values for your setup: + +- **Devices** + - Primary disk: `` (e.g., /dev/sda, /dev/nvme0n1) + - Backup disk: `` (e.g., /dev/sdb, /dev/nvme1n1) + - Primary EFI partition: `` (e.g., /dev/sda1, /dev/nvme0n1p1) + - Backup EFI partition: `` (e.g., /dev/sdb1, /dev/nvme1n1p1) + - Primary root partition: `` (e.g., /dev/sda2, /dev/nvme0n1p2) + - Backup root partition: `` (e.g., /dev/sdb2, /dev/nvme1n1p2) + - Primary swap partition: `` (e.g., /dev/sda3, /dev/nvme0n1p3) + - Backup swap partition: `` (e.g., /dev/sdb3, /dev/nvme1n1p3) + +- **UUIDs** + - Primary EFI UUID: `` (e.g., D167-0F46) + - Backup EFI UUID: `` (e.g., 08E8-A87C) + - Root BTRFS UUID: `` (e.g., 387526ec-f3bd-4fa8-a17e-e985121ada0b) + - Primary swap UUID: `` + - Backup swap UUID: `` + +## How It Works + +- The root filesystem is BTRFS RAID1 across two partitions. Either disk alone can serve reads and writes. +- Each disk has its own EFI partition. GRUB is installed on both physical disks. +- After every `apt` install or upgrade, an apt hook calls `update-efi-mirror`, which: + 1. Rsyncs the live `/boot/efi` to the backup EFI partition. + 2. Runs `grub-install` on both physical disks. +- Either disk can be removed and the system will still boot and run. + +## Paths + +- **Sync script**: `/usr/local/sbin/update-efi-mirror` +- **Apt hook**: `/etc/apt/apt.conf.d/99-update-efi-mirror` +- **fstab**: `/etc/fstab` + +## Setup Procedure + +### 1. Format the Disks + +**Verify which disks are present before touching anything** + +```bash +lsblk +lsblk -f +``` + +**Open `fdisk` on the backup disk** + +If the disk was previously used at a smaller capacity, the GPT backup table may be misaligned — `fdisk` will correct it on write. + +```bash +fdisk +``` + +Create a GPT partition table if not already present: + +``` +g +``` + +**Check the primary disk partition layout and note the exact sector boundaries** + +```bash +fdisk -l +``` + +This shows the `Start` and `End` sectors for each partition. Use these values when partitioning the backup disk so the layouts match exactly. + +**Create the three partitions to match the layout of the primary disk** + +| # | Size | Type | +| --- | --------- | ---------- | +| 1 | 830M | EFI System | +| 2 | ~12G | Linux fs | +| 3 | Remainder | Linux swap | + +Inside `fdisk`, the sequence is: + +``` +n # new partition + # enter the exact End sector from the primary disk to match partition sizes +t # change type +1 # select partition 1 +EFI System # set type to EFI +t # change type +3 # select partition 3 +Linux swap # set type to swap +w # write and exit +``` + +**Partition sizes must be at least as large as the corresponding primary partition** — the BTRFS replace will fail if the target partition is smaller than the source. + +**Format the new EFI partition** + +```bash +apt install dosfstools # if not installed +mkfs.fat -F32 +``` + +**Format the new swap partition** + +```bash +mkswap +``` + +**Check UUIDs of the new partitions** + +```bash +lsblk -f +``` + +### 2. Convert the Root Filesystem to BTRFS RAID1 + +**Add the backup partition to the BTRFS volume** + +```bash +btrfs device add / +``` + +**Convert to RAID1** + +```bash +btrfs balance start -mconvert=raid1 -dconvert=raid1 / +``` + +Monitor the balance: + +```bash +btrfs balance status / +``` + +**Verify the final layout** + +```bash +btrfs filesystem show / +btrfs fi usage / +``` + +### 3. Configure fstab + +Edit `/etc/fstab` to mount the primary EFI partition normally and document the backup EFI UUID in a commented-out entry. The script reads the backup UUID from this comment. + +**Edit fstab** + +```bash +nano /etc/fstab +``` + +The fstab should contain: + +``` +# Primary EFI — mounted at boot +UUID= /boot/efi vfat umask=0077 0 1 + +# Backup EFI — not auto-mounted, used by update-efi-mirror +#UUID= /boot/efi vfat umask=0077 0 1 + +# Root — BTRFS RAID1 (both partitions share the same UUID) +UUID= / btrfs defaults,noatime 0 1 + +# Swap — both disks +UUID= none swap sw 0 0 +UUID= none swap sw 0 0 +``` + +The backup EFI line must start with `#UUID=` — this is the format the script greps for: + +```bash +grep "^#UUID=" /etc/fstab | grep "/boot/efi" +``` + +**Reload systemd after editing fstab** + +```bash +systemctl daemon-reload +``` + +### 4. Install the Sync Script + +**Create the script** + +```bash +nano /usr/local/sbin/update-efi-mirror +``` + +Paste the contents of `update-efi-mirror.sh`. + +**Set ownership and permissions** + +```bash +chown root:root /usr/local/sbin/update-efi-mirror +chmod 755 /usr/local/sbin/update-efi-mirror +``` + +The script will: + +1. Detect the currently mounted EFI partition and its disk. +2. Read the backup EFI UUID from the `#UUID=` comment in `/etc/fstab`. +3. Mount the backup EFI to a temp directory, rsync all files from the live EFI, then unmount. +4. Run `grub-install --recheck` on both physical disks. + +### 5. Configure apt to Run the Script Post-Install + +**Create the apt hook** + +```bash +nano /etc/apt/apt.conf.d/99-update-efi-mirror +``` + +Add: + +``` +DPkg::Post-Invoke {"if [ -x /usr/local/sbin/update-efi-mirror ]; then /usr/local/sbin/update-efi-mirror; fi";}; +``` + +This runs the sync script after every `apt` operation that invokes `dpkg` — including kernel upgrades, which update `/boot/efi` with new initramfs and GRUB config. + +### 6. Test + +**Run the script manually** + +```bash +/usr/local/sbin/update-efi-mirror +``` + +Expected output: + +``` +Syncing EFI files: -> +EFI Files Sync Complete. +Updating GRUB bootloader on both physical disks... +Redundancy Complete: Files synced and GRUB updated on and . +``` + +**Test the apt hook** + +```bash +apt update +apt upgrade -y +``` + +The sync output should appear at the end of the upgrade, after GRUB regenerates its config. + +**Verify the backup EFI contents match** + +```bash +TMPMNT=$(mktemp -d) +mount -U "$TMPMNT" +diff -r /boot/efi/ "$TMPMNT/" +umount "$TMPMNT" +rmdir "$TMPMNT" +``` + +**Verify GRUB is installed on both disks** + +```bash +fdisk -l | grep -i efi +fdisk -l | grep -i efi +``` + +**`Optional` Boot from the backup disk** + +Swap the boot order in BIOS/UEFI to confirm the machine boots cleanly from ``. + +## Moving to a New Disk + +Use this procedure when replacing one of the two disks in the BTRFS RAID1 — for example when upgrading to a larger drive. + +**1. Partition the new disk** following [Step 1](#1-format-the-disks). + +**2. Find the device ID of the partition to be replaced:** + +```bash +btrfs filesystem show / +``` + +**3. Shrink the filesystem on the disk being replaced to fit the new partition:** + +```bash +btrfs filesystem resize : / +``` + +**4. Replace the old partition with the new one:** + +```bash +btrfs replace start / +btrfs replace status / +``` + +**5. Grow the new partition to max:** + +```bash +btrfs filesystem resize :max / +``` + +**6. Update fstab** if the backup EFI UUID has changed (new disk = new EFI UUID): + +```bash +lsblk -f +nano /etc/fstab +systemctl daemon-reload +``` + +**7. Run the sync script** to install GRUB on the new disk and populate its EFI partition: + +```bash +/usr/local/sbin/update-efi-mirror +``` + +**8. Verify** following [Step 6](#6-test).