> **Key improvement over Fedora 42:** libdnf5 integration means snapshots are created automatically whether you install packages via `dnf`, GNOME Software, or KDE Discover.
## Partitions and Subvolumes Layout
| Partition | Size | Filesystem | Mount Point |
| ----------- | --------- | ---------- | ----------- |
| `/dev/vda1` | 1 GiB | vfat | `/boot/efi` |
| `/dev/vda2` | Remaining | btrfs | (top-level) |
> No separate `/boot` partition — kernel lives inside Btrfs root so rollbacks also roll back the kernel.
> No swap partition — Fedora uses SwapOnZRAM automatically.
### Btrfs Subvolumes
| Name | Mount Point | Purpose |
| ------------- | --------------------- | ---------------------------------------------- |
| `root` | `/` | Core system files (snapshot-enabled) |
| `home` | `/home` | User data, isolated from system rollbacks |
| `opt` | `/opt` | Third-party software |
| `cache` | `/var/cache` | Package cache (excluded from snapshots) |
| `log` | `/var/log` | Preserved across rollbacks for diagnostics |
| `spool` | `/var/spool` | Transient data (excluded) |
| `tmp` | `/var/tmp` | Temporary files (excluded) |
| `containers` | `/var/lib/containers` | Container data (large and frequently changing) |
| `flatpak` | `/var/lib/flatpak` | Prevents snapshot bloat from Flatpak apps |
| `gdm` | `/var/lib/gdm` | GNOME login data (see note below) |
| `libvirt` | `/var/lib/libvirt` | VM data, isolated from rollbacks |
> **Desktop environment variants for the display manager subvolume:**
> - KDE Plasma → `/var/lib/plasmalogin` (name: `plasmalogin`)
> - XFCE → `/var/lib/lightdm` (`lightdm`) and `/var/lib/lightdm-data` (`lightdm-data`)
## Post-Installation Configuration
```bash
# Verify filesystem and layout
sudo btrfs filesystem show /
lsblk -p /dev/vda
sudo btrfs subvolume list /
# Enable Btrfs compression on all subvolumes (not set with custom layout)
sudo sed -i.bkp '/ btrfs / s/subvol=[^ ,]*/&,compress=zstd:1/' /etc/fstab
# Reboot to apply new mount options
reboot
# Optional: recompress existing data after reboot
sudo btrfs filesystem defragment -r -v -czstd /
sudo btrfs filesystem defragment -r -v -czstd /home
# Update system
sudo dnf update -y && reboot
```
## Set Up Snapper, grub-btrfs, and Btrfs Assistant
Fedora 44 uses an automated install script from the [SysGuides GitHub repo](https://github.com/SysGuides/sysguides-snapper-fedora):
```bash
sudo dnf install git -y
git clone https://github.com/SysGuides/sysguides-snapper-fedora
cd sysguides-snapper-fedora
chmod +x install.sh
./install.sh
```
The script installs and configures:
- **Snapper** — automatic pre/post transaction snapshots
- **grub-btrfs** — boot snapshots directly from GRUB menu
- **Btrfs Assistant** — graphical snapshot management
- Timeline and cleanup policies
- DNF5 integration (works with `dnf`, GNOME Software, and KDE Discover)
```bash
# Verify Snapper configs after install
snapper ls # root
snapper -c home ls # home
```
## Snapshot Management
```bash
# List snapshots
snapper ls # root
snapper -c home ls # home
# Delete a range of snapshots
sudo snapper delete 10-50
# Check actual disk usage of snapshots
sudo btrfs filesystem du -s --human-readable /.snapshots/*/snapshot
```
## Rollback (Btrfs Assistant GUI)
1. Boot into a snapshot from the GRUB **Fedora Linux snapshots** submenu.
2. Open **Btrfs Assistant**.
3. Go to **Snapper** → **Browse/Restore** tab.
4. Set **Select target** to `root`.
5. Choose the desired snapshot and click **Restore** → **Yes**.
6. Reboot — root subvolume is restored.
## Adding Subvolumes to a Default Fedora 44 Install
If Fedora 44 was installed using the default automatic disk layout, the installer only creates `root` and `home` subvolumes. Follow these steps to add the remaining subvolumes post-installation.
> [!warning] Boot from a Fedora Live USB
> **Do not perform the data migration steps (Step 3) while booted into the installed system.** Several directories are actively in use by the running OS:
> - `/var/log` — continuously written to by journald and other services
> - `/var/lib/gdm` — held open by the GDM display manager during a GNOME session
> - `/var/spool`, `/var/tmp` — may have active files
>
> Boot from a **Fedora Live USB** and mount the installed system's partition manually before proceeding with Step 3 onwards. Steps 1 and 2 (creating the subvolumes) can technically be done live, but it's simplest to do everything from the live environment in one pass.
>
> **Live environment workflow:** Boot the live USB → open a terminal → mount your Btrfs partition with `subvolid=5` → create subvolumes → migrate data → update `/etc/fstab` on the installed system → reboot into the installed OS.
### 1. Find Your Btrfs Partition and UUID
From the live environment, run:
```bash
lsblk -f
```
From the output, identify:
- The **raw partition** (e.g. `/dev/vda2`, `/dev/nvme0n1p3`) — `TYPE` will be `part`
- Whether LUKS is in use — `FSTYPE` will be `crypto_LUKS` on the partition, with a `luks-<UUID>` child device underneath it
- The **Btrfs UUID** — shown in the `UUID` column on the Btrfs line (the child mapper device if LUKS, or directly on the partition if not)
> Do **not** use `cat /etc/fstab` here — in the live environment that reads the live system's fstab, not the installed system's. The UUID must be read from `lsblk -f` output at this stage.
**No LUKS:** your device is the raw partition (e.g. `/dev/vda2`). Use this in all mount commands below.
**With LUKS:** your raw partition holds the LUKS container. The decrypted device will be at `/dev/mapper/luks-<partition-UUID>` once unlocked (or whatever name you choose in `cryptsetup open`). Use the mapper path in all mount commands below.
The Btrfs filesystem UUID (from `lsblk -f`) is what goes into the fstab entries in Step 5 — it is always the UUID of the decrypted Btrfs content, not the LUKS partition UUID.
### 2. Mount the Installed System
Set a variable for your device to avoid repeating it throughout the steps:
```bash
# No LUKS — use the raw partition directly:
DEVICE=/dev/vda2
# With LUKS — unlock the container first, then point to the mapper device:
sudo cryptsetup open /dev/vda2 btrfs-luks
DEVICE=/dev/mapper/btrfs-luks
```
Now mount the installed root subvolume (to access existing data) and the Btrfs top-level (to create new subvolumes):
```bash
# Mount the installed root subvolume
sudo mkdir -p /mnt/sysroot
sudo mount -o subvol=root $DEVICE /mnt/sysroot
# Mount the Btrfs top-level to create and populate subvolumes
sudo mkdir -p /mnt/btrfs
sudo mount -o subvolid=5 $DEVICE /mnt/btrfs
```
### 3. Create the Subvolumes
```bash
sudo btrfs subvolume create /mnt/btrfs/opt
sudo btrfs subvolume create /mnt/btrfs/cache
sudo btrfs subvolume create /mnt/btrfs/log
sudo btrfs subvolume create /mnt/btrfs/spool
sudo btrfs subvolume create /mnt/btrfs/tmp
sudo btrfs subvolume create /mnt/btrfs/containers
sudo btrfs subvolume create /mnt/btrfs/flatpak
sudo btrfs subvolume create /mnt/btrfs/gdm
sudo btrfs subvolume create /mnt/btrfs/libvirt
```
### 4. Migrate Existing Data
Copy existing data from the installed root into each new subvolume, then remove the original directory and recreate it as an empty mount point. All paths go through `/mnt/sysroot` (the installed system) and `/mnt/btrfs` (the new subvolumes).
```bash
# /var/log
sudo cp -arv /mnt/sysroot/var/log/. /mnt/btrfs/log/
sudo rm -rfv /mnt/sysroot/var/log && sudo mkdir -v /mnt/sysroot/var/log
# /var/cache
sudo cp -arv /mnt/sysroot/var/cache/. /mnt/btrfs/cache/
sudo rm -rfv /mnt/sysroot/var/cache && sudo mkdir -v /mnt/sysroot/var/cache
# /var/spool
sudo cp -arv /mnt/sysroot/var/spool/. /mnt/btrfs/spool/
sudo rm -rfv /mnt/sysroot/var/spool && sudo mkdir -v /mnt/sysroot/var/spool
# /var/tmp
sudo cp -arv /mnt/sysroot/var/tmp/. /mnt/btrfs/tmp/
sudo rm -rfv /mnt/sysroot/var/tmp && sudo mkdir -v /mnt/sysroot/var/tmp
# /opt
sudo cp -arv /mnt/sysroot/opt/. /mnt/btrfs/opt/
sudo rm -rfv /mnt/sysroot/opt && sudo mkdir -v /mnt/sysroot/opt
# /var/lib/gdm
sudo cp -arv /mnt/sysroot/var/lib/gdm/. /mnt/btrfs/gdm/
sudo rm -rfv /mnt/sysroot/var/lib/gdm && sudo mkdir -v /mnt/sysroot/var/lib/gdm
# /var/lib/flatpak
sudo cp -arv /mnt/sysroot/var/lib/flatpak/. /mnt/btrfs/flatpak/
sudo rm -rfv /mnt/sysroot/var/lib/flatpak && sudo mkdir -p /mnt/sysroot/var/lib/flatpak
# /var/lib/containers (likely empty on a fresh install)
sudo mkdir -p /mnt/sysroot/var/lib/containers
# /var/lib/libvirt (likely empty on a fresh install)
sudo mkdir -p /mnt/sysroot/var/lib/libvirt
```
### 5. Update /etc/fstab
Edit the **installed system's** fstab — not the live environment's:
```bash
sudo nano /mnt/sysroot/etc/fstab
```
Add the following entries. Replace `<UUID>` with the Btrfs UUID from Step 1. Match the mount options already present for `root` and `home` (typically `compress=zstd:1`):
```
UUID=<UUID> /opt btrfs subvol=opt,compress=zstd:1 0 0
UUID=<UUID> /var/cache btrfs subvol=cache,compress=zstd:1 0 0
UUID=<UUID> /var/log btrfs subvol=log,compress=zstd:1 0 0
UUID=<UUID> /var/spool btrfs subvol=spool,compress=zstd:1 0 0
UUID=<UUID> /var/tmp btrfs subvol=tmp,compress=zstd:1 0 0
UUID=<UUID> /var/lib/containers btrfs subvol=containers,compress=zstd:1 0 0
UUID=<UUID> /var/lib/flatpak btrfs subvol=flatpak,compress=zstd:1 0 0
UUID=<UUID> /var/lib/gdm btrfs subvol=gdm,compress=zstd:1 0 0
UUID=<UUID> /var/lib/libvirt btrfs subvol=libvirt,compress=zstd:1 0 0
```
### 6. Unmount and Reboot
```bash
sudo umount /mnt/btrfs
sudo umount /mnt/sysroot
sudo reboot
```
### 7. Restore SELinux Contexts and Verify
After booting into the installed system:
```bash
sudo restorecon -RFv /opt
sudo restorecon -RFv /var/cache /var/log /var/spool /var/tmp
sudo restorecon -RFv /var/lib/containers /var/lib/flatpak /var/lib/gdm /var/lib/libvirt
# Confirm all subvolumes are mounted correctly
sudo btrfs subvolume list /
lsblk -p /dev/vda
```
---
## References
- [Snapper (ArchWiki)](https://wiki.archlinux.org/title/Snapper)
- [Btrfs Assistant](https://gitlab.com/btrfs-assistant/btrfs-assistant)
- [sysguides-snapper-fedora (GitHub)](https://github.com/SysGuides/sysguides-snapper-fedora)