A small Btrfs/Snapper recovery utility for chrooting into a known-good root snapshot from a live environment.
snapshot-chroot records the root snapshot detected by a user's @reboot cron job, then uses that information during recovery to locate and chroot into the last known successfully booted snapshot.
If no saved snapshot is available, or if a different snapshot is desired, a snapshot number can be selected manually.
The project consists of two scripts:
save-last-snapshot.sh— records the Btrfs root snapshot currently mounted at/after boot.snapshot-chroot.sh— mounts a selected snapshot and prepares a recovery chroot from a live environment.
The saved snapshot record is stored in the user's home directory, which allows it to remain available independently of the root snapshot being recovered.
Example:
Snapshot: 1
Recorded: Mon Aug 10 08:50:45 PM CDT 2026
The current scripts are designed for a Btrfs/Snapper layout using:
@
@home
@/.snapshots
with Snapper root snapshots located at:
@/.snapshots/<snapshot-number>/snapshot
The recovery script also expects a separate EFI System Partition.
Example:
/dev/nvme0n1p2 Btrfs root filesystem
/dev/nvme0n1p1 EFI System Partition
Adjust these values in snapshot-chroot.sh to match the target system.
The recovery environment must provide:
bash
awk
btrfs
chroot
mount
umount
The installed system must use Btrfs and the snapshot layout described above.
snapshot-chroot.sh performs privileged mount, Btrfs, and chroot operations and must be run as root.
Copy save-last-snapshot.sh into the user's ~/bin directory and make it executable:
mkdir -p ~/bin
cp save-last-snapshot.sh ~/bin/
chmod +x ~/bin/save-last-snapshot.shAdd it to the user's crontab:
crontab -eAdd:
@reboot /home/USER/bin/save-last-snapshot.shReplace USER with the actual username.
After boot, save-last-snapshot.sh examines the Btrfs mount options for /.
If the running root filesystem is a Snapper snapshot matching:
@/.snapshots/<number>/snapshot
the script writes the snapshot number and timestamp to:
~/bin/last_snapshot
If the system is not currently running from a matching snapshot, the script exits without modifying the existing record. This preserves the last successfully recorded snapshot boot.
Before using the recovery script, edit the configuration section:
TARGET_USER="scottm"
ROOT_PARTITION="/dev/nvme0n1p2"
EFI_PARTITION="/dev/nvme0n1p1"
MOUNT_POINT="/mnt"Set:
TARGET_USERto the user whoselast_snapshotfile should be read.ROOT_PARTITIONto the Btrfs filesystem containing@,@home, and@/.snapshots.EFI_PARTITIONto the EFI System Partition.MOUNT_POINTto the temporary recovery mount point./mntis normally appropriate.
Boot a live Linux environment that has Btrfs tools installed.
Run:
sudo ./snapshot-chroot.shIf a valid last_snapshot record exists, the script reports it:
Last successfully booted snapshot: 1
Use snapshot 1 for the recovery chroot? [Y/n]
Press Enter or answer y to use it.
To select another snapshot, answer n and enter the desired snapshot number:
Enter snapshot number to use: 3
If no valid last_snapshot file exists, the script simply asks for a snapshot number.
Before building the chroot, snapshot-chroot.sh temporarily mounts the Btrfs top-level filesystem with subvolid=5.
The selected snapshot is then verified at:
@/.snapshots/<snapshot-number>/snapshot
If the snapshot does not exist, recovery stops and mounted filesystems are cleaned up.
The selected snapshot is checked before entering the recovery environment.
If it is already writable:
Snapshot 1 is writable.
recovery continues normally.
If the snapshot is read-only:
Snapshot 3 is read-only.
A writable snapshot is required for system repairs from this chroot.
Make snapshot 3 writable? [y/N]
Answering y changes the Btrfs ro property to false and continues.
Any other response leaves the snapshot read-only and cancels the recovery chroot.
Changing a read-only snapshot to writable modifies that snapshot.
Do this only when the selected snapshot is intended to become a writable recovery target. Consider the effect on any workflow that depends on the snapshot remaining unchanged, including Btrfs send/receive or archival snapshot strategies.
The script does not automatically change the snapshot back to read-only after recovery.
Once the target snapshot has been selected and verified, the script mounts:
selected root snapshot -> /mnt
@/.snapshots -> /mnt/.snapshots
@home -> /mnt/home
EFI System Partition -> /mnt/boot/efi
It also bind-mounts:
/dev
/dev/pts
/proc
/sys
/run
The resulting chroot therefore has access to the installed system, persistent home data, EFI files, and the root snapshot collection.
This makes operations such as the following possible from inside the recovery chroot:
update-initramfs -u
update-grubor inspection and management of other Btrfs snapshots through:
/.snapshots
For example:
btrfs property get -ts /.snapshots/3/snapshot roExit normally:
exitThe script then unmounts the recovery environment.
A cleanup trap is installed so that mounted filesystems are also cleaned up if the script exits early after recovery setup has begun.
Boot live environment
|
v
Mount @home
|
v
Read last_snapshot if available
|
v
Accept saved snapshot or select one manually
|
v
Mount Btrfs top level
|
v
Verify selected snapshot
|
v
Check read-only / writable state
|
+---- read-only ----> optionally make writable
|
v
Mount snapshot as recovery root
|
+---- mount @/.snapshots
+---- mount @home
+---- mount EFI
+---- bind /dev /proc /sys /run
|
v
Enter chroot
|
v
Exit and clean up mounts
snapshot-chroot/
├── save-last-snapshot.sh
├── snapshot-chroot.sh
└── last_snapshot
last_snapshot is an example of the state file generated by save-last-snapshot.sh.
snapshot-chroot does not perform a Snapper rollback and does not choose which snapshot should become the system's permanent root.
Its purpose is narrower: provide a predictable recovery chroot into a selected Btrfs/Snapper snapshot, with the last successfully booted snapshot offered as the default recovery target when available.
This project is currently being tested on Debian with Btrfs and Snapper.
Review the configuration carefully before using it on another system or Btrfs layout.