How to Install Fedora 38/39 with Snapshot and Rollback Support

By

Updated on

,

58

Comments

Install Fedora with Snapshot and Rollback Support - Feature Image

Fedora Linux 39 has been released! Fedora 39 brings numerous performance and security improvements, as well as hardware support. This release also includes the latest Gnome 45 desktop with improved styling.

In this guide, I will show you how to install Fedora 39 with the btrfs file system, as well as snapshot and rollback support. As a result, if you make a mistake with system configuration changes, package installations, or updates, you won't have to worry about losing data. Simply restore the snapshot before your problematic change, and you'll be fine.

I have updated this post for Fedora 39, which was originally intended for Fedora 38. In terms of btrfs snapshot and rollback support, nothing has changed between Fedora 38 and Fedora 39.

In case you've already followed a previous version of this tutorial and want to upgrade to Fedora 39, go straight to the section on upgrading at the end of this article and upgrade from Fedora 38 to Fedora 39. You don't have to do anything else.

Here’s a quick rundown of what needs to be done:

  1. Install Fedora 39 Workstation with btrfs file system by creating a main volume for the system root and a subvolume for the home.
  2. After the installation is complete, create additional subvolumes on the system root. These additional subvolumes will be created to keep certain directories out of the rollback regime. Some of these directories contain temporary files and caches, others contain data that you do not want to lose if you roll back the system root, and some should be in Read-Write mode when booting into a Read-only snapshot.
  3. Install and configure the snapper tool so that you can create, delete, and compare snapshots, as well as undo changes made between snapshots.
  4. Install and configure the grub-btrfs tool so that you can boot to any snapshot from the GRUB menu.
  5. Take a subvolume snapshot of the main volume and set the subvolume as the default '/' file system to make rollback much easier when using the snapper tool.
  6. And finally, enable automatic timeline snapshots of the '/' file system using the snapper tool.

If you want to install Fedora 38 with LUKS Full Disk Encryption, Snapshot and Rollback Support, please see my other article, How to Install Fedora 38/39 with Full Disk Encryption, Snapshot and Rollback Support.

So let's get started.

Table of Contents

1. Disk and Subvolumes Layout for Fedora

I'll use a hard disk with a capacity of 100 GIB. Fedora 39 suggests that the ESP be at least 500 MiB in size. So I'll create a 512 MiB EFI System Partition. You can, however, increase the size if necessary. I'll create a btrfs volume with the remaining disk space. Fedora creates a SwapOnZRAM during boot, so no separate swap partition is required.

This is how the disk partition looks.

NAME           SIZE   FSTYPE  LABEL    MOUNTPOINT
/dev/vda       100G
├─/dev/vda1    512M   vfat    EFI      /boot/efi
└─/dev/vda2   99.5G   btrfs   FEDORA   /

I will be installing the system root on the btrfs main volume (/dev/vda2). Then, on the system root, I'll create the following subvolumes to keep them out of root file system snapshots. In the end, this is how the disk layout looks.

NAME              MOUNTPOINT                 TYPE
[main]            /                          mainvolume
home              /home                      subvolume
opt               /opt                       subvolume
cache             /var/cache                 subvolume
crash             /var/crash                 subvolume
log               /var/log                   subvolume
spool             /var/spool                 subvolume
tmp               /var/tmp                   subvolume
www               /var/www                   subvolume
AccountsService   /var/lib/AccountsService   subvolume
gdm               /var/lib/gdm               subvolume
images            /var/lib/libvirt/images    subvolume
.mozilla          /home/$USER/.mozilla       subvolume

The directories for which subvolumes are created and the reasons for doing so are listed below.

/home

Contains user data. It is created to keep user data separate and also to avoid loss of user data on system root rollbacks. To learn more about /home, check this link: /home.

/opt

Contains applications installed by a third party. It is excluded to prevent these applications from being uninstalled during rollbacks. To learn more about /opt, check this link: /opt.

/var/cache, /var/crash, /var/tmp

Directories contain temporary files and caches. So they are created to be excluded from snapshots. Fedora also mounts /tmp with tmpfs at boot, so a separate subvolume for /tmp is unnecessary. To learn more, check these links: /var/cache/var/crash/var/tmp/tmp.

/var/log

Contains log files. It is created to avoid the loss of log data during rollbacks. To learn more about /var/log, check this link: /var/log.

/var/spool

Contains data that is awaiting some kind of later processing such as mail, mail queues, printing, printer spool, and so on. Created to avoid a loss of mail, printing, and spool data after a rollback. To learn more about /var/spool, check this link: /var/spool.

/var/www

Web server directory. It is created to keep hosted web server data separate and to avoid data loss on system root rollbacks.

/var/lib/AccountsService, /var/lib/gdm

Contains login user and Gnome display information. These directories must be writable at all times. When you try to boot a snapshot from the GRUB menu, you are booting into a read-only snapshot, which causes the system to hang just before the Gnome login screen appears.

In case you're using a desktop environment other than Gnome, it's necessary to replace the '/var/lib/gdm' with one that's specific to your desktop environment.

For KDE, it is '/var/lib/sddm'.

For XFCE, it might be '/var/lib/lightdm' and '/var/lib/lightdm-data'. I haven't tested.

To find out about other desktop environments, refer to this page.

/var/lib/libvirt/images

The default location for libvirt-managed virtual machine images. Excluded to avoid replacing virtual machine images with older versions during a rollback.

/home/$USER/.mozilla

By default, Fedora Workstation includes the Firefox browser. If you take a snapshot of your home directory and later undo any changes, you don't want to lose any new bookmarks, passwords, and other user data.

So, I'll create a new subvolume for the '.mozilla' directory. This keeps it separate from the home subvolume and prevents data loss during undo operations.

If you use the Chrome web browser, create a subvolume for the '/home/$USER/.config/google-chrome' directory.

Depending on your usage, you may also want to consider creating subvolumes in your home directory for the following directories:

  • GnuPG: /home/$USER/.gnupg
  • SSH: /home/$USER/.ssh
  • Thunderbird Mail: /home/$USER/.thunderbird

2. Install Fedora Workstation

Boot your system using the Fedora 39 Workstation installer in UEFI mode. On the welcome screen, select the Install to Hard Drive option. Next, select your LanguageKeyboard, and configure Time & Date. Following that, from the INSTALLATION SUMMARY screen, select Installation Destination.

You should now be on the INSTALLATION DESTINATION screen. To proceed, pick the Advanced Custom (Blivet-GUI) radio button and then hit the Done button.

On the BLIVET GUI PARTITIONING screen, create the partitions, file systems, and btrfs subvolumes necessary to install the Fedora 39 Workstation.

Install Fedora with Snapshot and Rollback Support - Blivet

First, you need to create and mount the EFI partition. Select the free space and click the + sign to create a partition.

Set the partition Size to 512 MiB, the Filesystem to EFI System Partition, and the Mountpoint to /boot/efi.

Install Fedora with Snapshot and Rollback Support - EFI Partition

Then, you need to create a btrfs volume where you can create all the subvolumes needed to install Fedora 39 Workstation.

Select the free space again and click on the + sign to create a Btrfs volume. Set the Filesystem to btrfs and the Mountpoint to /. I used the entire remaining space. However, you can specify the size you want for the btrfs volume.

Install Fedora with Snapshot and Rollback Support - BTRFS root partition

Next, you must create a home subvolume. (1) Select the Btrfs Volume from the left panel, and (2) click on the + sign on the right panel.

Install Fedora with Snapshot and Rollback Support - Create Subvolume

Create a home subvolume. Enter the Name as home and Mountpoint as /home. Click OK to finish.

Install Fedora with Snapshot and Rollback Support - Home Subvolume

I will create the remaining subvolumes when the installation is finished. This is because the Anaconda installer does not allow you to create subvolumes with slashes (/) in their names, such as var/log.

For now, click Done to finish creating subvolumes.

On the SUMMARY OF CHANGES screen, double-check that everything is properly defined. To finalize the changes, click the Accept Changes button.

Install Fedora with Snapshot and Rollback Support - Summary

You will be returned to the INSTALLATION SUMMARY screen. Press the Begin Installation button to start the installation process. The installation process will start. Just sit back and relax.

Install Fedora with Snapshot and Rollback Support - Installation

When the installation is finished, click the Finish Installation button and restart the system.

The last phase of the installation process will start. Click the Start Setup button to complete the remaining customization steps, such as setting a new login, password, etc.

You will then be logged into the Fedora 39 Workstation with the all-new Gnome 45 desktop interface.

Install Fedora with Snapshot and Rollback Support - Gnome 45

When booting your system, you may have noticed the following error message.

This is because you did not create a separate ext4 /boot partition and instead included it in the btrfs system root. GRUB preboot writes to /boot/grub2/grubenv if the boot was successful. This error occurs because of the GRUB btrfs.mod driver, unlike ext4, is read-only. To resolve this, open the Gnome terminal and execute the following command.

$ sudo grub2-editenv - unset menu_auto_hide

Set the btrfs volume label. I named the btrfs volume FEDORA, but you may name it whatever you want.

$ sudo btrfs filesystem label / FEDORA

$ sudo btrfs filesystem show /
Label: 'FEDORA'  uuid: ca244df3-0ddb-45c6-bd99-077d9bd81b04
	Total devices 1 FS bytes used 5.82GiB
	devid    1 size 99.50GiB used 10.02GiB path /dev/vda2

Your setup should look something like this.

$ lsblk -p
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
/dev/zram0  251:0    0  3.8G  0 disk [SWAP]
/dev/vda    252:0    0  100G  0 disk 
├─/dev/vda1 252:1    0  512M  0 part /boot/efi
└─/dev/vda2 252:2    0 99.5G  0 part /home
                                     /

And the subvolumes will look like this.

$ sudo btrfs subvolume list /
ID 256 gen 41 top level 5 path home
ID 257 gen 33 top level 5 path var/lib/machines

The var/lib/machines subvolume is created by systemd implicitly in Fedora Workstation for systemd-nspawn containers.

Enable the fastest mirrors to speed up package downloads. Copy the command from sudo to EOF, paste it into your terminal, and hit <Enter>.

$ sudo bash -c 'cat >> /etc/dnf/dnf.conf' <<EOF
defaultyes=True
fastestmirror=True
max_parallel_downloads=10
EOF

Clear all previous caches and update the local DNF metadata cache.

$ sudo dnf clean all
$ sudo dnf makecache

Install the packages listed below.

$ sudo dnf install vim inotify-tools make

Now, update your operating system.

$ sudo dnf update

And reboot your system.

$ sudo reboot

3. Create the Additional Subvolumes

I'll now proceed to create the remaining subvolumes on the system root. As previously stated, these subvolumes are created on the system root to avoid being included in the rollback regime because some of these directories contain temporary files and caches, others contain data that you do not want to lose if you rollback the system root, and some should be in Read-Write mode when booting into a Read-only snapshot.

Instead of manually creating subvolumes, I use the bash for loop. If you want to add or remove subvolumes, modify the SUBVOLUMES variable declaration.

#### Get the UUID of your btrfs system root.
$ ROOT_UUID="$(sudo grub2-probe --target=fs_uuid /)"

$ echo $ROOT_UUID
ca244df3-0ddb-45c6-bd99-077d9bd81b04

#### Get the btrfs subvolume mount options from your fstab.
$ OPTIONS="$(grep '/home' /etc/fstab | awk '{print $4}' | cut -d, -f2-)"

$ echo $OPTIONS
compress=zstd:1

#### Create a directory path. Only for other DEs; not required for Fedora Workstation.
$ sudo mkdir -vp /var/lib/libvirt

#### Declare rest of the subvolumes you want to create in the array.
#### Copy from 'SUBVOLUMES' to ')', paste it in terminal, and hit <Enter>.
$ SUBVOLUMES=(
    "opt"
    "var/cache"
    "var/crash"
    "var/log"
    "var/spool"
    "var/tmp"
    "var/www"
    "var/lib/AccountsService"
    "var/lib/gdm"
    "var/lib/libvirt/images"
    "home/$USER/.mozilla"
)

$ echo ${SUBVOLUMES[@]}
opt var/cache var/crash var/log var/spool var/tmp var/www var/lib/AccountsService var/lib/gdm var/lib/libvirt/images home/madhu/.mozilla

#### Run the for loop to create the subvolumes.
#### Copy from 'for' to 'done', paste it in terminal, and hit <Enter>.
$ for dir in "${SUBVOLUMES[@]}" ; do
    if [[ -d "/${dir}" ]] ; then
        sudo mv -v "/${dir}" "/${dir}-old"
        sudo btrfs subvolume create "/${dir}"
        sudo cp -ar "/${dir}-old/." "/${dir}/"
    else
        sudo btrfs subvolume create "/${dir}"
    fi
    sudo restorecon -RF "/${dir}"
    printf "%-41s %-24s %-5s %-s %-s\n" \
        "UUID=${ROOT_UUID}" \
        "/${dir}" \
        "btrfs" \
        "subvol=${dir},${OPTIONS}" \
        "0 0" | \
        sudo tee -a /etc/fstab
done

Ensure that you are the owner of the .mozilla directory.

$ sudo chown -R $USER: /home/$USER/.mozilla

$ ls -ldh /home/$USER/.mozilla
drwxr-xr-x. 1 madhu madhu 34 Nov  1 06:35 /home/madhu/.mozilla

Examine your /etc/fstab file. This is what it should look like. The UUID and username will be unique to your system.

$ cat /etc/fstab
...
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /                        btrfs defaults        0 0
UUID=39A2-F9C9                            /boot/efi                vfat  umask=0077,shortname=winnt 0 2
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /home                    btrfs subvol=home,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /opt                     btrfs subvol=opt,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /var/cache               btrfs subvol=var/cache,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /var/crash               btrfs subvol=var/crash,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /var/log                 btrfs subvol=var/log,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /var/spool               btrfs subvol=var/spool,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /var/tmp                 btrfs subvol=var/tmp,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /var/www                 btrfs subvol=var/www,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /var/lib/AccountsService btrfs subvol=var/lib/AccountsService,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /var/lib/gdm             btrfs subvol=var/lib/gdm,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /var/lib/libvirt/images  btrfs subvol=var/lib/libvirt/images,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /home/madhu/.mozilla     btrfs subvol=home/madhu/.mozilla,compress=zstd:1 0 0

Reload /etc/fstab to mount all the subvolumes.

$ sudo systemctl daemon-reload

$ sudo mount -va
/                        : ignored
/boot/efi                : already mounted
/home                    : already mounted
/opt                     : successfully mounted
/var/cache               : successfully mounted
/var/crash               : successfully mounted
/var/log                 : successfully mounted
/var/spool               : successfully mounted
/var/tmp                 : successfully mounted
/var/www                 : successfully mounted
/var/lib/AccountsService : successfully mounted
/var/lib/gdm             : successfully mounted
/var/lib/libvirt/images  : successfully mounted
/home/madhu/.mozilla     : successfully mounted

Check your subvolumes.

$ sudo btrfs subvolume list /
ID 256 gen 123 top level 5 path home
ID 257 gen 123 top level 5 path var/lib/machines
ID 258 gen 104 top level 5 path opt
ID 259 gen 123 top level 5 path var/cache
ID 260 gen 106 top level 5 path var/crash
ID 261 gen 123 top level 5 path var/log
ID 262 gen 123 top level 5 path var/spool
ID 263 gen 123 top level 5 path var/tmp
ID 264 gen 110 top level 5 path var/www
ID 265 gen 123 top level 5 path var/lib/AccountsService
ID 266 gen 123 top level 5 path var/lib/gdm
ID 267 gen 123 top level 5 path var/lib/libvirt/images
ID 268 gen 123 top level 256 path home/madhu/.mozilla

Your setup should now look somewhat like this.

$ lsblk -p
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
/dev/zram0  251:0    0  3.8G  0 disk [SWAP]
/dev/vda    252:0    0  100G  0 disk 
├─/dev/vda1 252:1    0  512M  0 part /boot/efi
└─/dev/vda2 252:2    0 99.5G  0 part /home/madhu/.mozilla
                                     /var/lib/libvirt/images
                                     /var/lib/gdm
                                     /var/lib/AccountsService
                                     /var/www
                                     /var/tmp
                                     /var/spool
                                     /var/log
                                     /var/crash
                                     /var/cache
                                     /opt
                                     /home
                                     /

Now that everything appears to be in order, you can delete the old directories. Copy from 'for' to 'done', paste it into the terminal, and hit <Enter>.

$ for dir in "${SUBVOLUMES[@]}" ; do
    if [[ -d "/${dir}-old" ]] ; then
        sudo rm -rvf "/${dir}-old"
    fi
done

All subvolumes have now been created.

4. Install and Configure Snapper

Install snapper and the optional package python3-dnf-plugin-snapper. The python3-dnf-plugin-snapper package allows you to create pre and post snapshots every time you install a package on the system with the dnf package manager.

$ sudo dnf install snapper python3-dnf-plugin-snapper

Create new snapper configurations named root and home for the btrfs volume at / and /home, respectively.

$ sudo snapper -c root create-config /
$ sudo snapper -c home create-config /home

The snapper configuration files will be saved in the /etc/snapper/configs/ directory.

Verify the snapper configuration files have been created.

$ sudo snapper list-configs
Config | Subvolume
-------+----------
home   | /home    
root   | /

Allow regular user to use snapper without requiring root privileges. Add your user name to the snapper's root and home configurations to set the ACL on the /.snapshots and /home/.snapshots directories.

$ sudo snapper -c root set-config ALLOW_USERS=$USER SYNC_ACL=yes
$ sudo snapper -c home set-config ALLOW_USERS=$USER SYNC_ACL=yes

Add the newly created snapshot subvolumes to the /etc/fstab file. The updated lines are in amber.

$ sudo vim /etc/fstab 
...
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /home/madhu/.mozilla     btrfs subvol=home/madhu/.mozilla,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /.snapshots              btrfs subvol=.snapshots,compress=zstd:1 0 0
UUID=ca244df3-0ddb-45c6-bd99-077d9bd81b04 /home/.snapshots         btrfs subvol=home/.snapshots,compress=zstd:1 0 0

Reload the /etc/fstab file.

$ sudo systemctl daemon-reload
$ sudo mount -va

Your setup should look something like this.

$ lsblk -p /dev/vda
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
/dev/vda    252:0    0  100G  0 disk 
├─/dev/vda1 252:1    0  512M  0 part /boot/efi
└─/dev/vda2 252:2    0 99.5G  0 part /home/.snapshots
                                     /.snapshots
                                     /home/madhu/.mozilla
                                     /var/www
                                     /var/spool
                                     /var/tmp
                                     /var/log
                                     /var/lib/libvirt/images
                                     /var/lib/gdm
                                     /var/lib/AccountsService
                                     /var/crash
                                     /var/cache
                                     /opt
                                     /home
                                     /

And your subvolumes will look like this.

$ sudo btrfs subvolume list /
ID 256 gen 129 top level 5 path home
ID 257 gen 123 top level 5 path var/lib/machines
ID 258 gen 104 top level 5 path opt
ID 259 gen 127 top level 5 path var/cache
ID 260 gen 106 top level 5 path var/crash
ID 261 gen 131 top level 5 path var/log
ID 262 gen 123 top level 5 path var/spool
ID 263 gen 126 top level 5 path var/tmp
ID 264 gen 110 top level 5 path var/www
ID 265 gen 123 top level 5 path var/lib/AccountsService
ID 266 gen 123 top level 5 path var/lib/gdm
ID 267 gen 123 top level 5 path var/lib/libvirt/images
ID 268 gen 123 top level 256 path home/madhu/.mozilla
ID 269 gen 129 top level 5 path .snapshots
ID 270 gen 129 top level 256 path home/.snapshots

Disable the indexing of the .snapshots directories by updatedb. It is enabled by default, which can cause significant slowdown and excessive memory usage if you have a large number of snapshots.

$ echo 'PRUNENAMES = ".snapshots"' | sudo tee -a /etc/updatedb.conf

Enable snapshot booting by appending the SUSE_BTRFS_SNAPSHOT_BOOTING="true" option to the /etc/default/grub file.

$ echo 'SUSE_BTRFS_SNAPSHOT_BOOTING="true"' | sudo tee -a /etc/default/grub

You must also make changes to the /boot/efi/EFI/fedora/grub.cfg file now that snapshot booting is enabled.

$ sudo sed -i '1i set btrfs_relative_path="yes"' /boot/efi/EFI/fedora/grub.cfg

Finally, update the grub.cfg file.

$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg

Later, I'll enable snapper timeline snapshots. For now, the snapper configuration is complete.

List the snapshots for / volume. For the root, you may use snapper -c root ls or simply snapper ls. Both provide the same output.

$ snapper ls
 # | Type   | Pre # | Date | User | Cleanup | Description | Userdata
---+--------+-------+------+------+---------+-------------+---------
0  | single |       |      | root |         | current     |

List the snapshots for /home subvolume.

$ snapper -c home ls
 # | Type   | Pre # | Date | User | Cleanup | Description | Userdata
---+--------+-------+------+------+---------+-------------+---------
0  | single |       |      | root |         | current     |

At this stage, you do not have any snapshots, we will create some later.

5. Install and Configure Grub-Btrfs

The grub-btrfs package adds 'Fedora Linux snapshots' to the GRUB menu and allows you to test a snapshot in read-only mode before rolling back to it in read-write mode.

Clone the grub-btrfs repository.

$ git clone https://github.com/Antynea/grub-btrfs

The setup is pre-configured to work with Arch and Gentoo out of the box. You must make a few changes to the grub-btrfs config file to make it work with Fedora.

$ cd grub-btrfs

$ sed -i '/#GRUB_BTRFS_SNAPSHOT_KERNEL/a GRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS="systemd.volatile=state"' config
$ sed -i '/#GRUB_BTRFS_GRUB_DIRNAME/a GRUB_BTRFS_GRUB_DIRNAME="/boot/grub2"' config
$ sed -i '/#GRUB_BTRFS_MKCONFIG=/a GRUB_BTRFS_MKCONFIG=/sbin/grub2-mkconfig' config
$ sed -i '/#GRUB_BTRFS_SCRIPT_CHECK=/a GRUB_BTRFS_SCRIPT_CHECK=grub2-script-check' config

Then install it.

$ sudo make install

Update grub.cfg and enable the grub-btrfsd.service.

$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg
$ sudo systemctl enable --now grub-btrfsd.service

You will receive the 'No snapshots found' error since you have not yet created any snapshots, but don't worry, it will function properly after you do.

Your grub-btrfs installation is now complete. You may now delete the cloned grub-btrfs repository.

$ cd ..
$ rm -rvf grub-btrfs

6. Create a System Root Snapshot and Set It as the Default

Now that everything in Fedora has been installed and configured, it is time to take a subvolume snapshot of the main volume and set the subvolume as the default ‘/‘ file system. By manually creating a subvolume snapshot of the main volume and making it the default, you can easily rollback without having to specify the snapshot number and the 'ambit' during the rollback when using the snapper tool.

Create a directory named '1' in the /.snapshots directory.

$ sudo mkdir -v /.snapshots/1

Create an XML file called info.xml in the /.snapshots/1/ directory. Copy the following command from sudo to EOF, paste it into your terminal, and hit the <Enter> button.

$ sudo bash -c "cat > /.snapshots/1/info.xml" <<EOF
<?xml version="1.0"?>
<snapshot>
  <type>single</type>
  <num>1</num>
  <date>$(date -u +"%F %T")</date>
  <description>first root subvolume</description>
</snapshot>
EOF

Verify that the date is set properly and is in the Coordinated Universal Time (UTC) format.

$ cat /.snapshots/1/info.xml
<?xml version="1.0"?>
<snapshot>
  <type>single</type>
  <num>1</num>
  <date>2023-11-06 07:58:38</date>
  <description>first root subvolume</description>
</snapshot>

Now, create a read-write subvolume snapshot of the system root in the /.snapshots/1/ directory.

$ sudo btrfs subvolume snapshot / /.snapshots/1/snapshot

Get the subvolid of the /.snapshots/1/snapshot subvolume.

$ sudo btrfs inspect-internal rootid /.snapshots/1/snapshot
271

Using subvolid 271, set the /.snapshots/1/snapshot subvolume as the default subvolume for the root (/) filesystem.

$ sudo btrfs subvolume set-default 271 /

And reboot your system.

$ sudo reboot

After rebooting, confirm that the /.snapshots/1/snapshot subvolume is indeed the default for the / filesystem.

$ sudo btrfs subvolume get-default /
ID 271 gen 170 top level 269 path .snapshots/1/snapshot

Now check the snapshots in snapper.

$ snapper ls
 # | Type   | Pre # | Date                                | User | Cleanup | Description          | Userdata
---+--------+-------+-------------------------------------+------+---------+----------------------+---------
0  | single |       |                                     | root |         | current              |         
1* | single |       | Monday 06 November 2023 01:28:38 PM | root |         | first root subvolume |

As you can see, the /.snapshots/1/snapshot subvolume is also visible as snapshot #1 in snapper. The asterisk (*) indicates that this snapshot is the default and is currently active.

The installation of Fedora 39 with snapshot and rollback support is now complete. You can now begin taking snapshots.

7. Snapper Tests

I'll run some tests here to make sure everything is in working order and that there are no problems.

Test 1: Undo the Changes Made by the DNF Installer

In this test, I will use the dnf package manager to install a small package named ps_mem. I'll check the system after it is installed to see what changes were made. I'll then attempt to undo the changes and see if I can get the system back to its pre-installation state.

Install the ps_mem package. It displays the core memory used per program (not per process).

$ sudo dnf install ps_mem

Run the ps_mem program to see if it was installed successfully.

$ sudo ps_mem
 Private  +   Shared  =  RAM used	Program

144.0 KiB +  13.5 KiB = 157.5 KiB	fusermount3
196.0 KiB +  12.5 KiB = 208.5 KiB	inotifywait
292.0 KiB +  14.5 KiB = 306.5 KiB	mcelog
...
 48.2 MiB +   6.0 MiB =  54.2 MiB	gnome-software
190.6 MiB +   1.8 MiB = 192.4 MiB	packagekitd
234.3 MiB +  24.1 MiB = 258.4 MiB	gnome-shell
---------------------------------
                          1.1 GiB
=================================

Check the snapper for snapshots.

$ snapper ls
 # | Type   | Pre # | Date                                | User | Cleanup | Description                 | Userdata
---+--------+-------+-------------------------------------+------+---------+-----------------------------+---------
0  | single |       |                                     | root |         | current                     |         
1* | single |       | Monday 06 November 2023 01:28:38 PM | root |         | first root subvolume        |         
2  | pre    |       | Monday 06 November 2023 01:40:51 PM | root | number  | /usr/bin/dnf install ps_mem |         
3  | post   |     2 | Monday 06 November 2023 01:40:53 PM | root | number  | /usr/bin/dnf install ps_mem |

As you can see, the ps_mem package has pre (#2) and post (#3) snapshots.

Let's take a look at the changes it made to the system between snapshots #2 and #3.

$ snapper status 2..3
+..... /usr/bin/ps_mem
c..... /usr/lib/sysimage/rpm/rpmdb.sqlite-shm
c..... /usr/lib/sysimage/rpm/rpmdb.sqlite-wal
+..... /usr/share/doc/ps_mem
+..... /usr/share/doc/ps_mem/LICENSE
+..... /usr/share/man/man1/ps_mem.1.gz
c..... /var/lib/dnf/history.sqlite-shm
c..... /var/lib/dnf/history.sqlite-wal
-..... /var/lib/dnf/rpmdb_lock.pid

Now I'll undo the changes.

$ sudo snapper undochange 2..3
create:1 modify:4 delete:4

Check again to ensure that the ps_mem package was successfully uninstalled.

$ sudo ps_mem
sudo: ps_mem: command not found

Cool! The undo was successful. But, because I want to keep the package ps_mem, I'll undo the changes again. This time between snapshots #3 and #2.

$ sudo snapper undochange 3..2
create:4 modify:4 delete:1

Now run ps_mem again to see if it exists.

$ sudo ps_mem
 Private  +   Shared  =  RAM used	Program

144.0 KiB +  13.5 KiB = 157.5 KiB	fusermount3
196.0 KiB +  12.5 KiB = 208.5 KiB	inotifywait
292.0 KiB +  14.5 KiB = 306.5 KiB	mcelog
...
 48.2 MiB +   6.0 MiB =  54.2 MiB	gnome-software
190.6 MiB +   1.8 MiB = 192.4 MiB	packagekitd
234.3 MiB +  24.1 MiB = 258.4 MiB	gnome-shell
---------------------------------
                          1.1 GiB
=================================

Test 1 is successful.

Test 2: Undo Any Changes Made to Individual Files

Assume you're configuring something and editing a configuration file. Then you realize you messed up the configuration file. You want to see what changes you made to the original file and possibly wish you could undo the changes.

You can use snapper to undo not only all changes between two snapshots, but also a single file.

In this test, I will simply delete the last line of the /etc/hosts file. Then I'll compare it to the same file in snapshot #3 to see what changed and if I can undo all of the changes and restore it to its original state.

This is how the original /etc/hosts file looks.

$ cat /etc/hosts
# Loopback entries; do not change.
# For historical reasons, localhost precedes localhost.localdomain:
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
# See hosts(5) for proper format and other examples:
# 192.168.1.10 foo.mydomain.org foo
# 192.168.1.13 bar.mydomain.org bar

Now I'll remove the last line.

$ sudo sed -i '$d' /etc/hosts

$ cat /etc/hosts
# Loopback entries; do not change.
# For historical reasons, localhost precedes localhost.localdomain:
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
# See hosts(5) for proper format and other examples:
# 192.168.1.10 foo.mydomain.org foo

Now that I have removed the last line, using the snapper tool, compare the /etc/hosts file with the one in snapshot #3.

$ snapper diff 3..0 /etc/hosts
--- /.snapshots/3/snapshot/etc/hosts	2022-11-27 20:56:24.000000000 +0530
+++ /etc/hosts	2023-04-28 21:14:25.578325998 +0530
@@ -4,4 +4,3 @@
 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
 # See hosts(5) for proper format and other examples:
 # 192.168.1.10 foo.mydomain.org foo
-# 192.168.1.13 bar.mydomain.org bar

The number 0 in the command 3..0 represents the current snapshot, while the number 3 represents snapshot #3.

As you can see in the last line, the /etc/hosts file in the current snapshot is missing that line compared to the one in snapshot #3. If you want to learn how to read the output, take a look at the man pages man diff and man snapper.

To replace the /etc/hosts file with the one in snapshot #3, use the following command.

$ sudo snapper undochange 3..0 /etc/hosts
create:0 modify:1 delete:0

Check to see if the /etc/hosts file has indeed been rolled back.

$ cat /etc/hosts
# Loopback entries; do not change.
# For historical reasons, localhost precedes localhost.localdomain:
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
# See hosts(5) for proper format and other examples:
# 192.168.1.10 foo.mydomain.org foo
# 192.168.1.13 bar.mydomain.org bar

Test 2 is successful.

Test 3: Create Manual Pre-Post Snapshots and Undo the Changes

In my previous article, I performed a manual pre-post snapshots test for installing a package with Gnome Software. The concept for both tests is the same. If you want, you can also run that test.

In this test, I will begin by creating manual 'pre' snapshots of the / and /home directories. Then I'll install a small package called Color Picker (gcolor3) from GitHub by compiling it from the source file. When I'm finished, regardless of whether the compiling was successful or not, I'll create 'post' snapshots for the previously created 'pre' snapshots. I'll then look at the changes it made to the system between the pre-post snapshots and, finally, undo everything.

Create a manual 'pre' snapshot for both the / and /home directories.

$ snapper -c root create -t pre -c number -d 'Pre Color Picker'
$ snapper -c home create -t pre -c number -d 'Pre Color Picker'

List the snapshots.

$ snapper ls
 # | Type   | Pre # | Date                                | User  | Cleanup | Description                 | Userdata
---+--------+-------+-------------------------------------+-------+---------+-----------------------------+---------
0  | single |       |                                     | root  |         | current                     |         
1* | single |       | Monday 06 November 2023 01:28:38 PM | root  |         | first root subvolume        |         
2  | pre    |       | Monday 06 November 2023 01:40:51 PM | root  | number  | /usr/bin/dnf install ps_mem |         
3  | post   |     2 | Monday 06 November 2023 01:40:53 PM | root  | number  | /usr/bin/dnf install ps_mem |         
4  | pre    |       | Monday 06 November 2023 02:02:54 PM | madhu | number  | Pre Color Picker            |

$ snapper -c home ls
 # | Type   | Pre # | Date                                | User  | Cleanup | Description      | Userdata
---+--------+-------+-------------------------------------+-------+---------+------------------+---------
0  | single |       |                                     | root  |         | current          |         
1  | pre    |       | Monday 06 November 2023 02:03:02 PM | madhu | number  | Pre Color Picker |

Install the pre-requisite packages before compiling the source file.

$ sudo dnf install meson gcc-c++ libhandy-devel libportal-devel \
    libportal-gtk3-devel

Compile the source.

$ git clone https://github.com/Hjdskes/gcolor3.git
$ cd gcolor3
$ meson setup build
$ ninja-build -C build
$ sudo ninja-build -C build install

Make sure the Color Picker package has been installed properly. Enter gcolor3 into the terminal and hit <Enter>. The Color Picker app must be open and appear as shown.

Install Fedora with Snapshot and Rollback Support - Gcolor3

Now that you have successfully installed the Color Picker application, close the application and create 'post' snapshots for the / and /home directories.

$ snapper -c home create -t post --pre-number 1 -c number -d 'Post Color Picker'
$ snapper -c root create -t post --pre-number 4 -c number -d 'Post Color Picker'

List the snapshots.

$ snapper -c root ls
 # | Type   | Pre # | Date                                | User  | Cleanup | Description                                                                            | Userdata
---+--------+-------+-------------------------------------+-------+---------+----------------------------------------------------------------------------------------+---------
0  | single |       |                                     | root  |         | current                                                                                |         
1* | single |       | Monday 06 November 2023 01:28:38 PM | root  |         | first root subvolume                                                                   |         
2  | pre    |       | Monday 06 November 2023 01:40:51 PM | root  | number  | /usr/bin/dnf install ps_mem                                                            |         
3  | post   |     2 | Monday 06 November 2023 01:40:53 PM | root  | number  | /usr/bin/dnf install ps_mem                                                            |         
4  | pre    |       | Monday 06 November 2023 02:02:54 PM | madhu | number  | Pre Color Picker                                                                       |         
5  | pre    |       | Monday 06 November 2023 02:05:52 PM | root  | number  | /usr/bin/dnf install meson gcc-c++ libhandy-devel libportal-devel libportal-gtk3-devel |         
6  | post   |     5 | Monday 06 November 2023 02:06:21 PM | root  | number  | /usr/bin/dnf install meson gcc-c++ libhandy-devel libportal-devel libportal-gtk3-devel |         
7  | post   |     4 | Monday 06 November 2023 02:08:23 PM | madhu | number  | Post Color Picker                                                                      |

$ snapper -c home ls
 # | Type   | Pre # | Date                                | User  | Cleanup | Description       | Userdata
---+--------+-------+-------------------------------------+-------+---------+-------------------+---------
0  | single |       |                                     | root  |         | current           |         
1  | pre    |       | Monday 06 November 2023 02:03:02 PM | madhu | number  | Pre Color Picker  |         
2  | post   |     1 | Monday 06 November 2023 02:08:11 PM | madhu | number  | Post Color Picker |

Review the changes made to the system between the pre and post snapshots.

$ snapper -c home status 1..2
+..... /home/madhu/.config/gcolor3
+..... /home/madhu/.config/gcolor3/config.ini
+..... /home/madhu/gcolor3
+..... /home/madhu/gcolor3/build
+..... /home/madhu/gcolor3/build/build.ninja
...
+..... /home/madhu/.local/share/gnome-shell/application_state
c..... /home/madhu/.local/share/gvfs-metadata/root
-..... /home/madhu/.local/share/gvfs-metadata/root-3616f454.log
+..... /home/madhu/.local/share/gvfs-metadata/root-54385136.log

$ snapper -c root status 4..7
c..... /boot/grub2/grub-btrfs.cfg
c..... /boot/grub2/grub.cfg
+..... /etc/alternatives/ld
c..... /etc/ld.so.cache
+..... /usr/bin/addr2line
...
+..... /usr/share/xml/dbus-1/catalog.xml
+..... /usr/share/xml/dbus-1/introspect.dtd
+..... /usr/share/zsh/site-functions/_meson
+..... /usr/share/zsh/site-functions/_ninja
+..... /var/lib/alternatives/ld
c..... /var/lib/dnf/history.sqlite
c..... /var/lib/dnf/history.sqlite-shm
c..... /var/lib/dnf/history.sqlite-wal

This is the total number of files added, removed, or modified.

$ snapper -c home status 1..2 | wc -l
278

$ snapper -c root status 4..7 | wc -l
13913

I'll now undo the changes in the / and /home directories.

$ sudo snapper -c home undochange 1..2
create:1 modify:3 delete:274

$ sudo snapper -c root undochange 4..7
create:0 modify:13 delete:13900

The Color Picker package will be completely removed from the system.

Log out and then log back in.

$ gnome-session-quit

Check again to see if the Color Picker has been completely removed.

$ gcolor3
bash: gcolor3: command not found...

Since you removed the Color Picker package, there is no reason to keep its pre-post snapshots if you do not intend to use it again. So you can delete those snapshots.

$ snapper -c home delete 1-2
$ snapper -c root delete 4-7

Test 3 is successful.

Test 4: Rollback to a Previous Snapshot from the GRUB Menu

In this rollback test, I will delete the most critical files and directories on which the Linux operating system relies. These include Linux kernel and initramfs files in the /boot directory, the /etc directory, which contains all configuration files, and the /usr directory, which contains all drivers, kernel modules, and library files.

Once I delete these files and directories, I will be unable to issue any commands because the Linux OS is pretty much dead, and the system will undoubtedly fail the next time it boots. So I'll hard boot the system and see if I can save the day by rolling back to a working snapshot.

So, before I delete them, here's how they appear.

$ sudo du -sch /boot /etc /usr
254M	/boot
33M	/etc
5.9G	/usr
6.1G	total

Now delete the files and directories.

$ sudo rm -rvf /boot/{vmlinuz,initramfs}* /etc /usr

Boom!!! All critical files have been removed. Your Linux system is no longer operational. Reboot the system. Your system should now fail to boot and display something like this.

Install Fedora with Snapshot and Rollback Support - Boot Error

Return to the GRUB menu and this time boot from snapshot #3.

Install Fedora with Snapshot and Rollback Support - Snapshots Menu
Install Fedora with Snapshot and Rollback Support - Select Snapshot #3
Install Fedora with Snapshot and Rollback Support - Select Latest Kernel

Open the terminal and make sure everything is back to normal.

$ sudo ls /boot /etc /usr

Because you booted into the snapshot, the '/' file system is read-only.

$ sudo btrfs property get -ts /
ro=true

Now that everything appears to be operating properly, it is time to roll back this snapshot in read-write mode.

$ snapper ls
 # | Type   | Pre # | Date                                | User | Cleanup | Description                 | Userdata
---+--------+-------+-------------------------------------+------+---------+-----------------------------+---------
0  | single |       |                                     | root |         | current                     |         
1+ | single |       | Monday 06 November 2023 01:28:38 PM | root |         | first root subvolume        |         
2  | pre    |       | Monday 06 November 2023 01:40:51 PM | root | number  | /usr/bin/dnf install ps_mem |         
3- | post   |     2 | Monday 06 November 2023 01:40:53 PM | root | number  | /usr/bin/dnf install ps_mem |

As you can see from the output, snapshot #1 has a '+' symbol, indicating that it is the default subvolume, whereas snapshot #3 has a '-' symbol, indicating that it is the currently booted subvolume.

$ sudo snapper rollback
Ambit is classic.
Creating read-only snapshot of default subvolume. (Snapshot 4.)
Creating read-write snapshot of current subvolume. (Snapshot 5.)
Setting default subvolume to snapshot 5.

Now, reboot your system.

$ sudo reboot

The first thing you should do after a rollback is to update the grub.cfg file so that the GRUB menu snapshots are always in sync.

$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg

Check the system once again.

$ sudo du -sch /boot /etc /usr
254M	/boot
33M	/etc
5.9G	/usr
6.1G	total

$ sudo btrfs property get -ts /
ro=false

$ snapper ls
 # | Type   | Pre # | Date                                | User | Cleanup | Description                 | Userdata     
---+--------+-------+-------------------------------------+------+---------+-----------------------------+--------------
0  | single |       |                                     | root |         | current                     |              
1  | single |       | Monday 06 November 2023 01:28:38 PM | root | number  | first root subvolume        |              
2  | pre    |       | Monday 06 November 2023 01:40:51 PM | root | number  | /usr/bin/dnf install ps_mem |              
3  | post   |     2 | Monday 06 November 2023 01:40:53 PM | root | number  | /usr/bin/dnf install ps_mem |              
4  | single |       | Monday 06 November 2023 03:42:54 PM | root | number  | rollback backup of #1       | important=yes
5* | single |       | Monday 06 November 2023 03:42:54 PM | root |         | writable copy of #3         |

$ sudo btrfs subvolume list /
ID 256 gen 281 top level 5 path home
ID 257 gen 162 top level 5 path var/lib/machines
ID 258 gen 96  top level 5 path opt
ID 259 gen 278 top level 5 path var/cache
ID 260 gen 97  top level 5 path var/crash
ID 261 gen 283 top level 5 path var/log
ID 262 gen 277 top level 5 path var/spool
ID 263 gen 281 top level 5 path var/tmp
ID 264 gen 99  top level 5 path var/www
ID 265 gen 277 top level 5 path var/lib/AccountsService
ID 266 gen 278 top level 5 path var/lib/gdm
ID 267 gen 101 top level 5 path var/lib/libvirt/images
ID 268 gen 117 top level 256 path home/madhu/.mozilla
ID 269 gen 283 top level 5 path .snapshots
ID 270 gen 262 top level 256 path home/.snapshots
ID 271 gen 272 top level 269 path .snapshots/1/snapshot
ID 272 gen 193 top level 269 path .snapshots/2/snapshot
ID 273 gen 273 top level 269 path .snapshots/3/snapshot
ID 274 gen 272 top level 269 path .snapshots/4/snapshot
ID 275 gen 281 top level 269 path .snapshots/5/snapshot

$ sudo btrfs subvolume get-default /
ID 275 gen 281 top level 269 path .snapshots/5/snapshot

You successfully restored the system with the latest working snapshot in read and write mode.

Test 4 is successful.

8. Make a Snapshot the New System Root

Now that you've tested the snapper undo and rollback features and are hopefully satisfied with the results, you might want to set one of the snapshots as the new default system root and resume normal operating system use.

But first, let me show you how to determine how much space each snapshot takes up on your disk.

$ sudo btrfs filesystem du -s --human-readable /.snapshots/*/snapshot
     Total   Exclusive  Set shared  Filename
  55.34MiB       0.00B    55.34MiB  /.snapshots/1/snapshot
   5.90GiB    32.00KiB     5.84GiB  /.snapshots/2/snapshot
   5.90GiB    52.00KiB     5.84GiB  /.snapshots/3/snapshot
  55.34MiB       0.00B    55.34MiB  /.snapshots/4/snapshot
   5.90GiB   244.00KiB     5.84GiB  /.snapshots/5/snapshot

As you can see from the output above, snapshot #1 has an exclusive size of 0 bytes. This is because, as you may recall, I deleted all of the files recursively. Snapshot #4 is also 0 bytes in size because it is a read-only duplicate of snapshot #1.

To find out how the 'Total' and 'Set shared' values are calculated, see the man page man btrfs-filesystem.

Now, let's return to making a snapshot the new system root.

$ snapper ls
 # | Type   | Pre # | Date                                | User | Cleanup | Description                 | Userdata     
---+--------+-------+-------------------------------------+------+---------+-----------------------------+--------------
0  | single |       |                                     | root |         | current                     |              
1  | single |       | Monday 06 November 2023 01:28:38 PM | root | number  | first root subvolume        |              
2  | pre    |       | Monday 06 November 2023 01:40:51 PM | root | number  | /usr/bin/dnf install ps_mem |              
3  | post   |     2 | Monday 06 November 2023 01:40:53 PM | root | number  | /usr/bin/dnf install ps_mem |              
4  | single |       | Monday 06 November 2023 03:42:54 PM | root | number  | rollback backup of #1       | important=yes
5* | single |       | Monday 06 November 2023 03:42:54 PM | root |         | writable copy of #3         |

The output indicates that snapshot #5 is the default subvolume, and since it is operational, you can simply delete the remaining snapshots and move on.

However, I will use snapshot #2 as the default because it is a 'pre' snapshot that was created just before ps_mem was installed and is clean.

So, first, delete all of the snapshots except #2. You cannot delete snapshot #5 because it is the active one.

$ snapper delete 1
$ snapper delete 3-4

$ snapper ls
 # | Type   | Pre # | Date                                | User | Cleanup | Description                 | Userdata
---+--------+-------+-------------------------------------+------+---------+-----------------------------+---------
0  | single |       |                                     | root |         | current                     |         
2  | pre    |       | Monday 06 November 2023 01:40:51 PM | root | number  | /usr/bin/dnf install ps_mem |         
5* | single |       | Monday 06 November 2023 03:42:54 PM | root |         | writable copy of #3         |    

Create a directory named '1' in the /.snapshots directory.

$ sudo mkdir -v /.snapshots/1

Copy the info.xml file from /.snapshots/2/ to /.snapshots/1/.

$ sudo cp -v /.snapshots/2/info.xml /.snapshots/1/

Edit the /.snapshots/1/info.xml file and change the content from this...

$ sudo cat /.snapshots/1/info.xml
<?xml version="1.0"?>
<snapshot>
  <type>pre</type>
  <num>2</num>
  <date>2023-11-06 08:10:51</date>
  <description>/usr/bin/dnf install ps_mem</description>
  <cleanup>number</cleanup>
</snapshot>

...to this. Changes are in amber.

$ sudo cat /.snapshots/1/info.xml
<?xml version="1.0"?>
<snapshot>
  <type>single</type>
  <num>1</num>
  <date>2023-11-06 08:10:51</date>
  <description>new root subvolume</description>
</snapshot>

Create a read-write subvolume snapshot of snapshot #2 in the /.snapshots/1/ directory.

$ sudo btrfs subvolume snapshot /.snapshots/2/snapshot /.snapshots/1/snapshot

Get the subvolid of the /.snapshots/1/snapshot subvolume.

$ sudo btrfs inspect-internal rootid /.snapshots/1/snapshot
276

Using subvolid 276, set the /.snapshots/1/snapshot subvolume as the default subvolume for the root (/) filesystem.

$ sudo btrfs subvolume set-default 276 /

Then reboot.

$ sudo reboot

After rebooting, confirm that the /.snapshots/1/snapshot subvolume is indeed the default for the / filesystem.

$ sudo btrfs subvolume get-default /
ID 276 gen 418 top level 269 path .snapshots/1/snapshot

And is writable.

$ sudo btrfs property get -ts /
ro=false

Take a look at the snapper now.

$ snapper ls
 # | Type   | Pre # | Date                                | User | Cleanup | Description                 | Userdata
---+--------+-------+-------------------------------------+------+---------+-----------------------------+---------
0  | single |       |                                     | root |         | current                     |         
1* | single |       | Monday 06 November 2023 01:40:51 PM | root |         | new root subvolume          |         
2  | pre    |       | Monday 06 November 2023 01:40:51 PM | root | number  | /usr/bin/dnf install ps_mem |         
5  | single |       | Monday 06 November 2023 03:42:54 PM | root |         | writable copy of #3         | 

As you can see, snapshot #1 is the default. You can now delete the remaining snapshots.

$ snapper delete 2-5

$ snapper ls
 # | Type   | Pre # | Date                                | User | Cleanup | Description        | Userdata
---+--------+-------+-------------------------------------+------+---------+--------------------+---------
0  | single |       |                                     | root |         | current            |         
1* | single |       | Monday 06 November 2023 01:40:51 PM | root |         | new root subvolume |         

$ sudo btrfs filesystem du -s --human-readable /.snapshots/*/snapshot
     Total   Exclusive  Set shared  Filename
   5.90GiB   268.00KiB     5.84GiB  /.snapshots/1/snapshot

You're done.

9. Enable Automatic Timeline Snapshots

Now that you've finished everything, you can enable automatic timeline snapshots. When the timeline is enabled, a snapshot is created once every hour. Once per day, the timeline cleanup algorithm cleans up the snapshots.

It is enabled by default in both the root and home configurations. Enable it only for the system root and disable it for the home. See the Arch Wiki page on 'Automatic timeline snapshots' for more information.

$ sudo snapper -c home set-config TIMELINE_CREATE=no
$ sudo systemctl enable --now snapper-timeline.timer
$ sudo systemctl enable --now snapper-cleanup.timer

That's all. Every hour from now on, a 'single' snapshot will be created and cleaned up every other day.

$ snapper ls
 # | Type   | Pre # | Date                                | User | Cleanup  | Description        | Userdata
---+--------+-------+-------------------------------------+------+----------+--------------------+---------
0  | single |       |                                     | root |          | current            |         
1* | single |       | Monday 06 November 2023 01:40:51 PM | root |          | new root subvolume |
2  | single |       | Monday 06 November 2023 02:00:01 PM | root | timeline | timeline           |           

To stop timeline snapshots, disable the snapper timers.

$ sudo systemctl disable --now snapper-timeline.timer
$ sudo systemctl disable --now snapper-cleanup.timer

The installation of Fedora 39 with snapshot and rollback support is now complete.

10. Issues and Possible Solutions

Issue: This usually occurs when a kernel update has just been released and all of the kernel's supporting files have not yet been propagated to a repository mirror near you.

This is caused by the kernel parameter '{extra_cmdline}'. The '{extra_cmdline}' parameter is added to the kernel when you add the 'SUSE_BTRFS_SNAPSHOT_BOOTING=true' key to the /etc/default/grub file.

Solution: From the GRUB menu, select the kernel version you want to boot, and then press 'e' to modify the command.

Go to the line that starts with the word 'linux', and move the parameter '{extra_cmdline}' to the end of the line. The parameter '{extra_cmdline}' should always be at the end of the line.

From this:

Install Fedora with Snapshot and Rollback Support - Issue 1

To this:

Install Fedora with Snapshot and Rollback Support - Solution 1

Then, on your keyboard, press Ctrl+x. You will be successfully booted into the operating system. Next, launch the terminal and execute the following command.

$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg

Reboot the computer to ensure the problem has been resolved.

11. Upgrade Fedora 38 to Fedora 39

If you've already followed an earlier version of this tutorial and installed Fedora 38 and want to upgrade to Fedora 39, this section is for you.

Update the local DNF metadata cache.

$ sudo dnf makecache

Update your Fedora 38 release. This is important. Do not skip this step.

$ sudo dnf upgrade --refresh

After the updates have been installed, reboot your computer.

$ sudo reboot

After rebooting, open the terminal and run the following command to upgrade your Fedora 38 operating system to the most recent Fedora 39 version.

$ sudo dnf system-upgrade download --releasever=39

Once the upgrades have been downloaded, trigger the upgrade process. This will immediately reboot your computer, with no countdown or confirmation. So, before issuing the following command, close all other programs and save your work.

$ sudo dnf system-upgrade reboot

Once the upgrade process completes, your system will reboot again into the updated release version of Fedora 39.

If you want to learn more about the upgrade process, check out this link.

12. Watch on YouTube

The video was made for Fedora 38, but it is also applicable to Fedora 39. Nothing has changed between Fedora 38 and Fedora 39 in terms of btrfs snapshot and rollback support.

Thank you for engaging with this content.

If you like my work and want to thank me or encourage me to do more, you can buy me a coffee! The coffee will give me the "kick" I need to work even harder to bring you even more interesting Linux guides and articles.

Comments

58 responses to “How to Install Fedora 38/39 with Snapshot and Rollback Support”

  1. Rafli Sugiarto Avatar
    Rafli Sugiarto

    I got this notification from sealert when the snapshot was created:

    ```
    SELinux is preventing snapperd from getattr access on the sock_file /.snapshots/63/snapshot/var/lib/mysql/mysql.sock.

    Plugin: catchall
    SELinux denied access requested by snapperd. It is not expected that this
    access is required by snapperd and this access may signal an intrusion attempt.
    It is also possible that the specific version or configuration of the
    application is causing it to require additional access.

    If you believe that snapperd should be allowed getattr access on the mysql.sock sock_file by default.
    You should report this as a bug.
    You can generate a local policy module to allow this access.
    Allow this access for now by executing:
    # ausearch -c 'snapperd' --raw | audit2allow -M my-snapperd
    # semodule -X 300 -i my-snapperd.pp
    ```

    Do I have to follow the command's instructions to granting it access?

    1. Madhu Desai Avatar

      Snapperd is a Snapper DBus daemon. Giving permission will not cause any harm.

  2. Torsten Ruger Avatar

    This is very very cool, thank you. (please add a coffee button)

    Not having snapper was the only qualm i had with leaving Suse behind. Fedora is so solid on the system updates that i had no problem, until i recently manually managed to screw my system. And very timely found this, hoping that it will save me from my ignorance in the future.
    While i understand the concepts here there is no way i could have done it myself.

    For the perfectionist that you seem to be (because the guide is really is perfect), there are two mini things: The vim action has your private UID's in there (just to keep people sharp, i'm sure:-)
    The second was that setting a new default seems a bit long winded, is that because you want to bring it back to 1 (ie about numbering). Wouldn't it be much easier to just keep going with the numbers, remove the old and set the new to current?

    Anyway, quibbles, i really just wanted to thank you and buy you a coffee
    Torsten

    1. Madhu Desai Avatar

      Thank you very much for your appreciation.

      I wrote the article using the KVM Virtual Machine. So no worries about UUID.

      The reason for the default snapshot is that no subvolume is set as 'default' in Fedora by default. When you roll back a snapshot in snapper for the first time, that snapshot becomes the default subvolume. By manually creating a first snapshot of the main volume and making it the default, you can rollback easily without having to specify the snapshot number and the 'ambit' during the rollback process. It is just a snapper thing and is for convenience only.

      Regarding 'Buy me a Coffee,' I have applied for it because it requires some documentation so that I may make international transactions. I may add the option next month.

  3. Michael Sharp Avatar

    Sir, it appears you are total Fedora guru!
    The only part of this install that was not identical was my fstab did not contain the UUIDs of the newly created subvolumes, so I just copied them in and of course it worked.
    Thank you.

  4. Konstantin Avatar
    Konstantin

    I am facing a bit of a problem: I broke something when trying to enable hibernate according to this guide, and the system would refuse to boot, so I booted into the last working snapshot and did a snapper rollback. Then I tried following section 8 of the article, but when I ran

    snapper delete 1
    

    I got this error:

    Deleting snapshot failed.
    

    So my system is working just fine, but my default subvolume is now .snapshots/728/snapshot. I'd like to set my default subvolume to .snapshots/1/snapshot like it was previously. How can I do that without risking to delete my actual root directory?

    1. Madhu Desai Avatar

      Is there an asterisk symbol (*) in the output of the 'snapper ls' command for snapshot #728? If so, try deleting the snapshot 1 with the sudo prefix. Permission issues can arise at times.

      Examine the /var/log/snapper.log log file as well. It'll give you a hint.

      1. Konstantin Avatar
        Konstantin

        Finally figured it out! The issue was a nested subvolume (for swap) in /.snapshots/1/snapshot. After deleting it, I was able to delete it and move on. Now, do you have any ideas on how to enable hibernate on this setup?

  5. Max J. Avatar
    Max J.

    Hello Madhu, thanks for your awesome work! I made it to work on Debian using lots of this content you have provided. Could you elaborate a bit on part 6. and 8., test 4? I don't quite really get what I'm donig when I follow your instructions about setting default btrfs subvolume snapshots... thanks a lot!

    1. Madhu Desai Avatar

      You don't have to create the default subvolume. By default, no btrfs subvolume is set as the default (btrfs subvolume get-default /). When you rollback a snapshot in snapper, that subvolume then becomes the default. By manually creating a first snapshot of the main volume and making it the default, you can rollback without having to specify the snapshot number and the ambit during the rollback process.

      Section 8 is also the same. I simply made one of the snapshots the new default and the first one, and deleted the remaining snapshots.

      In test 4, I deliberately broke the system and rolled back to a previous working snapshot.

      1. Max J. Avatar
        Max J.

        thank you!

  6. fuzz Avatar
    fuzz

    hello, i folllow your tutorial and success, then im trying to change my display manager (im using sddm before) to lightdm and greetd, i follow tutorial number 3 to create another subvolume, change the SUBVOLUMES variable to "/var/lib/lightdm" and "/var/lib/greetd". it can create the subvolume and add that to /etc/fstab, but i got this error when trying to mount
    /                       : ignored
    /boot/efi               : already mounted
    /home                   : already mounted
    /opt                    : already mounted
    /var/cache              : already mounted
    /var/crash              : already mounted
    /var/log                : already mounted
    /var/spool              : already mounted
    /var/tmp                : already mounted
    /var/www                : already mounted
    /var/lib/AccountsService : already mounted
    /var/lib/sddm           : already mounted
    /var/lib/libvirt/images : already mounted
    /home/fuzz/.mozilla     : already mounted
    /.snapshots             : already mounted
    /home/.snapshots        : already mounted
    mount: /var/lib/greetd: mount(2) system call failed: No such file or directory.
          dmesg(1) may have more information after failed mount system call.
    mount: /var/lib/lightdm: mount(2) system call failed: No such file or directory.
          dmesg(1) may have more information after failed mount system call.
    am i doing it wrong?

    1. Madhu Desai Avatar

      What is the output of the command?
      btrfs subvolume list /

      Do the subvolumes appear in the output?

      1. fuzz Avatar
        fuzz

        yes, the subvolumes do appear, here the ouput
        https://pastebin.com/wVgP3KC9

        1. Madhu Desai Avatar

          The output indicates that the two subvolumes are not top-level (ID=5).

          First, rename or delete the two subvolumes.

          Assuming that the btrfs partition is /dev/vda2, mount the btrfs volume with id=5 option.
          sudo mount -o subvolid=5 /dev/vda2 /mnt

          After that, create the two subvolumes.
          sudo btrfs subvolume create /mnt/var/lib/greetd
          sudo btrfs subvolume create /mnt/var/lib/lightdm

          Un mount the btrfs volume
          sudo umount /mnt

          Check the subvolumes once more. The two subvolumes must be visible with level 5. Then, update the /etc/fstab file. It should work fine.

  7. Mukund Avatar
    Mukund

    Thanks for the guide, tests for undoing changes on dnf work well.
    But, while trying to make changes to individual files and testing snapper, I am getting the following permission denied error. snapper diff 4..0 /etc/hosts IO Error (open failed path://.snapshots/4/snapshot/root/.cache/keyring-X95291/control errno:13 (Permission denied))

    1. Madhu Desai Avatar

      It appears that the problem is unrelated to snapper. Can you restart the system and check again to see if the problem has been resolved?

  8. rsza Avatar
    rsza

    I just want to say this is one of the best guides I have seen out there for implementing something in linux overall , super well done ! and your youtube video is really good too . Great job

    1. Madhu Desai Avatar

      Thank you so much. I'm so glad that you liked it.

      1. rsza Avatar
        rsza

        wondering if you could help , im right at the end of part 6 but snapper is not playing ball .

        [user@fedora ~]$ sudo mkdir -v /.snapshots/1
        mkdir: created directory '/.snapshots/1'
        [user@fedora ~]$ sudo nano /.snapshots/1/info.xml
        cat /.snapshots/1/info.xml
        sudo bash -c "cat > /.snapshots/1/info.xml" <<EOF
        <?xml version="1.0"?>
        <snapshot>
         <type>single</type>
         <num>1</num>
         <date>$(date -u +"%F %T")</date>
         <description>first root subvolume</description>
        </snapshot>
        EOF
        [user@fedora ~]$ sudo btrfs subvolume snapshot / /.snapshots/1/snapshot
        Create a snapshot of '/' in '/.snapshots/1/snapshot'
        [user@fedora ~]$ sudo btrfs inspect-internal rootid /.snapshots/1/snapshot
        271
        [user@fedora ~]$ sudo btrfs subvolume set-default 271 /
        [user@fedora ~]$ **sudo reboot**

        sudo btrfs subvolume get-default /
        ID 271 gen 430 top level 269 path .snapshots/1/snapshot

        snapper ls
         # | Type  | Pre # | Date | User | Cleanup | Description | Userdata
        ---+--------+-------+------+------+---------+-------------+---------
        0 | single |      |     | root |        | current    |        

        I tried to start the service but it ended up creating "2" and still ignoring "1" , should I just mv 2 to 1 ?

      2. rsza Avatar
        rsza

        no worries I realized I skimmed at an important part and messed up info.xml ! lol thanks man

        snapper ls
         # | Type  | Pre # | Date                    | User | Cleanup | Description         | Userdata
        ---+--------+-------+--------------------------+------+----------+----------------------+---------
        0 | single |      |                         | root |         | current             |        
        1* | single |      | Wed 30 Aug 2023 11:59:57 | root |         | first root subvolume |        
        2 | single |      | Wed 30 Aug 2023 11:18:52 | root | timeline | timeline            |        

  9. cris Avatar
    cris

    Could you make a tuto but for debian.
    I can not make the default snapshot be booted by default.

    1. cris Avatar
      cris

      Made it, Also in debian is super more simple.

      vim /etc/default/grub
      GRUB_CMDLINE_LINUX_DEFAULT="quiet rootflags=noatime"
      
      
      
  10. Konstantin Avatar
    Konstantin

    sorry... regarding my previous comment, I made a mistake and psd didn't actually pick up the directory correctly. It seems psd doesn't support flatpak's sandbox system since flatpak firefox shows a “profile not accessible” error when enabling psd with the correct configuration.

  11. Konstantin Avatar
    Konstantin

    If you use any browsers as flatpak:

    1. quit any open browser
    2. install Flatseal
    3. add "home:rw" entry in the filesystem section
    4. copy ~/.var/app/[flatpak_id]/[profile_dir] to ~/ (optional: delete the original profile folder)
    5. open the browser (it should open your profile as usual)
    6. go to about:profiles and open your profile dir: it should work now
    7. follow section 3 of the article, replacing the SUBVOLUMES array with the new profile directory; before reloading systemctl, open /etc/fstab and check if everything looks right
    8. profit!

    I would also recommend checking out profile-sync-daemon, you should be able to use just fine now. Check out https://wiki.archlinux.org/title/Firefox/Tweaks for more info on how to optimize Firefox and its derivates further.

  12. Josh Avatar
    Josh

    Hello, if I remember correctly, you planned to write the article about proper dualboot with Windows on a single disk. Any updates on that? Thanks.

    1. Madhu Desai Avatar

      Yes, I remember it really well. In fact, I attempted to set up snapper and grub-btrfs for proper rollback on Ubuntu. But I failed miserably because the Ubuntu installation is stubborn. I tried every method available to me (Using GUI installer and chroot) to install Ubuntu system root (/) as the btrfs main volume, but they all failed miserably. In Ubuntu, the system root has to be a subvolume.

      Disappointed, I returned to work on a YouTube video for Fedora 38 LUKS. I'll upload the video to YouTube tomorrow and return to the dualboot as soon as I can.

      Whatever the outcome is, I'll let you know by the weekend. Sorry about that, and thank you for your patience.

    2. Madhu Desai Avatar

      I'm working hard to get Ubuntu to rollback from a snapshot. However, it is taking longer than I anticipated. I'm stuck with grub-btrfs. I'm not very familiar with Ubuntu, so it's quite difficult for me. Hopefully, I'll be successful in the end and be able to publish the article. You'll have to wait a little longer, I suppose. If I don't succeed, I plan to use the manual rollback method. So, let's see what happens. I apologize for the bad news.

      1. Robbie Avatar
        Robbie

        The following article seems to have done something similar on Ubuntu:
        https://moslehian.com/posts/2023/2-reliable-btrfs-snapshots-snapper-debian-ubuntu/

  13. Juan Manuel Lobos Avatar
    Juan Manuel Lobos

    Same as Kronik, I had a fedora 38 with LUKS automatically unlocked by TPM, and after install and make grub-btrfs changes, Grub gone fubar, no boot at all.

     lsblk -p /dev/nvme0n1
    NAME                           MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    /dev/nvme0n1                       259:0  0 476,9G 0 disk  
    ├─/dev/nvme0n1p1                     259:1  0   2G 0 part /boot/efi
    ├─/dev/nvme0n1p2                     259:2  0   2G 0 part /boot
    ├─/dev/nvme0n1p3                     259:3  0 456,9G 0 part  
    │ └─/dev/mapper/luks-d0f1fb6d-f3c6-4cd7-a4ed-f2b3f18b8444 253:1  0 456,9G 0 crypt /var
    │                                          /home
    │                                          /
    └─/dev/nvme0n1p4                     259:4  0  16G 0 part  
     └─/dev/mapper/luks-12e0f0bc-7ef5-4de5-91ac-1b467b946868 253:0  0  16G 0 crypt [SWAP]
    (I did not create any additionals subvols, I wanted to test with full root )
    btrfs subvolume list /
    ID 256 gen 10259 top level 5 path var
    ID 257 gen 10259 top level 5 path home
    ID 258 gen 10259 top level 5 path root
    ID 259 gen 10083 top level 256 path var/lib/machines

    grubby --info=DEFAULT
    index=0
    kernel="/boot/vmlinuz-6.3.8-200.fc38.x86_64"
    args="ro rootflags=subvol=root rd.driver.blacklist=nouveau modprobe.blacklist=nouveau resume=/dev/mapper/luks-12e0f0bc-7ef5-4de5-91ac-1b467b946868 rd.luks.uuid=luks-d0f1fb6d-f3c6-4cd7-a4ed-f2b3f18b8444 rd.luks.uuid=luks-12e0f0bc-7ef5-4de5-91ac-1b467b946868 rd.luks.options=tpm2-device=auto rhgb quiet nvidia-drm.modeset=1"
    root="UUID=feb1d19f-eb14-489d-8bd5-71a35af29c4f"
    initrd="/boot/initramfs-6.3.8-200.fc38.x86_64.img"
    title="Fedora Linux (6.3.8-200.fc38.x86_64) 38 (Workstation Edition)"
    id="4a94a83fdcd2489684c3afb8f39acd03-6.3.8-200.fc38.x86_64"

    1. Madhu Desai Avatar

      From what I see in the outputs, you have created a separate /boot partition (/dev/nvme0n1p2). In this tutorial, I deliberately did not create a separate /boot partition and instead included boot files in the main system root. You are experiencing this issue as a result of your separate /boot partition.

      You also do not need to create a separate swap partition (/dev/nvme0n1p4). Fedora creates a swap on zram on boot, which is better to a swap within a partition.

      1. Juan Manuel Lobos Avatar
        Juan Manuel Lobos

        Allright. It's just this wasn't an installation from scratch but a recent installation either way. I did that on purpose to encrypt the swap partition as well, I'll be considering turning it off and use zram instead.
        So basically if I manage to put the grub partition inside the root / it'll all work out fine (?)
        Thanks for your time and replying so soon.

  14. KronikPillow Avatar
    KronikPillow

    Following the guide, after first boot and running sudo dnf update, after the restart im unable to boot

    1. Madhu Desai Avatar

      What is the error message you're getting?

      1. KronikPillow Avatar
        KronikPillow

        That the kernel is not found ... Thats, fresh install, configure dnf, update, reboot and gone ... Followed exact steps of guide, didnt get to creating extra subvolumes

        1. Madhu Desai Avatar

          Can you share the output of the following commands? Replace /dev/vda with your disk.

          lsblk -p /dev/vda
          btrfs subvolume list /
          grubby --info=DEFAULT
          cat /boot/efi/EFI/fedora/grub.cfg

          1. KronikPillow Avatar
            KronikPillow

            lsblk -p /dev/sda
            btrfs subvolume list /
            grubby --info=DEFAULT
            cat /boot/efi/EFI/fedora/grub.cfg

            NAME       MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
            /dev/sda     8:0   0 232.9G 0 disk
            ├─/dev/sda1  8:1   0  512M 0 part /boot/efi
            └─/dev/sda2  8:2   0 232.4G 0 part /home
                                                 /

            ID 256 gen 34 top level 5 path home
            ID 257 gen 25 top level 5 path var/lib/machines

            index=0
            kernel="/boot/vmlinuz-6.2.9-300.fc38.x86_64"
            args="ro rhgb quiet"
            root="UUID=ce6aa617-c626-4561-9417-e127083bdeaf"
            initrd="/boot/initramfs-6.2.9-300.fc38.x86_64.img"
            title="Fedora Linux (6.2.9-300.fc38.x86_64) 38 (Workstation Edition)"
            id="bd70c7f84b654b0e9a1d2347be1d8358-6.2.9-300.fc38.x86_64"

            search --no-floppy --fs-uuid --set=dev ce6aa617-c626-4561-9417-e127083bdeaf
            set prefix=($dev)/boot/grub2

            export $prefix
            configfile $prefix/grub.cfg

          2. Madhu Desai Avatar

            It seems like everything is fine. I ran another test in virtualization. Everything went perfectly on my end.

            Your kernel, as I can see, is 6.2.9-300. It is currently 6.3.5-200. It's possible that the mirrors closest to you weren't fully updated. Please check after the system has been updated once more.

            From the GRUB menu, on the kernel line. press 'c'
            In the grub prompt, enter the following:
            grub> chainloader (hd0,gpt1)/efi/fedora/grubx64.efi
            grub> boot

            Update the system one more time. Then, update the grub.cfg.
            grub2-mkconfig -o /boot/grub2/grub.cfg

            Reboot the computer. Hopefully, everything will go smoothly this time.

  15. KronikPillow Avatar
    KronikPillow

    wouldn't excluding /boot/grub directory solve the grub problem? also, could you elaborate the why the systemd.volatile=state is necessary? Cuz I didn't have to do this on Arch Linux at all (now im switching to fedora to test your guide, and to try out Fedora 38) ...
    here is my Arch install script, maybe you can help me understand what volatile is and why it's needed on Fedora, and not needed on Arch?
    btw, here is my OpenSuse like btrfs style layout for Arch Linux, with full snapper-rollback without the need to use --ambit classic or anything else, it works exactly the same like on https://github.com/kronikpillow/arch-install/tree/main .... check the 100-pre-user-subvolume.sh, and the other scripts ...
    also, I wouldn't chattr +C anything, the files in libvirt/images get automatically created with chattr +C by default, even when chattr +C is not enabled on the directory itself because it's handled by qemu/kvm/virt-manager

    1. Madhu Desai Avatar

      I checked your subvolume layout, and it looks great. You probably can't create such a layout in Fedora using the default Anaconda installer. I'll have to try installing Fedora using the 'dnf --installroot' command, as I did in my other blog 'How to Install Fedora 38 with Full Disk Encryption, Snapshot and Rollback Support', and see how it goes.

      I notice that your scripts do not mention installing the GNOME graphical desktop environment. Fedora, too, will have no trouble booting into a read-only snapshot without a graphical desktop. However, a problem arises, particularly when you install the GNOME desktop. I have not tested for other DEs. You cannot boot into a read-only snapshot with "gdm" set as a graphical login in Fedora. I'm not sure how it works in Arch Linux.

      So, I set the kernel parameter 'systemd.volatile=state'. It causes the system to boot with the root filesystem as read-only and /var mounted as a writable tempfs ram-disk. In simple terms, the system will behave similarly to a Live Linux media without persistence.

      It would be ideal when you want to rollback a snapshot and only want to ensure that everything is as it should be in that snapshot without attempting to modify anything in the system root.

      It worked perfectly. But, even with 'systemd.volatile=state' set, some of my readers reported that they couldn't boot into a ready-only snapshot. As a result, I had to create two separate subvolumes from the system root snapshot regime: '/var/lib/AccountsService' and '/var/lib/gdm'.

      About chattr, yes, chattr +C is automatically set for the image directory. So I guess I'll have to get rid of that part. However, resetting will not cause any harm.

      Thank you for bringing it to my attention.

      1. KronikPillow Avatar
        KronikPillow

        Yes my script still is not converted to Fedora, and no display manager in my script as I don't use one on Arch as usually I only have 1 Window Manager installed, so my base system is setup via posted scripts, and then my post base system install script varies depending on what I want to use in the current install.
        Although when I used SDDM as a login manager I didn't have a problem booting into Arch from a read-only snapshot...

        You are right, you can not create such a layout with Anaconda, plus Anaconda sucks, I do not understand why Fedora keeps pushing the distro with it, everytime I want to create a subvolume with it Anaconsa freezes and asks me to wait or kill it ... I never did a chroot install of Fedora, tried to grasp the approach with your guide with encryption, but couldn't figure it out, and didn't have enough time to keep tinkering yet and figure it out, so if doing a guide of a chroot install, with a layout I suggested without encryption it would be awesome. ... I did fail at 1 part in my script, I tried to make /home/kronikpillow rollback possible same like it is on @, but failed ... Now I'm gonna try the same with @/home if it fails, I'll just move my 150-pre-user-subvolume into 100-pre-user-subvolume and make my home layout part of the root subvolume... I'll post an update once I find out as I'm in active testing ...

        Regarding other users who couldn't boot, I noticed in your guide that you only chown & chmod 2 directories, while multiple directory permissions in your /var subvolumes are set incorrectly, for example, gdm should be owned by gdm:gdm, there are others that you set incorrectly but can't remember which one as I'm on mobile while writing this reply, but I will post my findings about it later today as well, I know this because I compared the permissions of the default install vs the permissions of the subvolumes in their place ... Maybe setting correct user and group and chmod permissions will solve the problem

        1. KronikPillow Avatar
          KronikPillow

          another thing that came to my mind is that grub-btrfs now has a kernel flag called grub-btrfs-overlay-fs that allows you to boot a read only var ... which could completely solve the users not being able to boot, and the need for /var/lib/AccountService and /var/lib/gdm
          on the other hand, going back to your approach
          you should also chmod 1770 /var/lib/gdm and chown /var/lib/gdm gdm:gdm

    2. Madhu Desai Avatar

      Oh, I forgot about the grub. I'm assuming you're referring to the 'sparse file not allowed' error message. The grub menu auto hide feature is enabled by default in Fedora, and you must disable it anyway so that the grub menu is always visible and you can boot into snapshots at any time.

  16. Vikramaditya Avatar
    Vikramaditya

    Could you please make one guide with snapshot and rollback-support for Fedora's default (automatic) partition layout i.e root and home as subvolumes of main btrfs volume? Thanks 🙂

    1. Madhu Desai Avatar

      I tried this setup several times. Trust me, I tried at least 20-30 times. But every time I rolled back, I couldn't mount other subvolumes. It's most likely related to the 'SUSE_BTRFS_SNAPSHOT_BOOTING' option. I'm not sure. But I will try again and see if I missed anything. If I come up with something useful, I'll definitely write a guide for that setup as well.

      1. Vikramaditya Avatar
        Vikramaditya

        Thanks. I tried twice but couldn't make it work either. Snapshot booting is not visible under grub although I set it to TRUE by following your guide. I will wait for your updated guide. 🙂

  17. alon Avatar
    alon

    I have solved it via chatgpt's help 😀
    sudo mkdir /var/lib/libvirt
    then

    #!/bin/bash

    # Get the UUID of your btrfs system root.
    ROOT_UUID="$(sudo grub2-probe --target=fs_uuid /)"

    # Get the btrfs subvolume mount options from your fstab.
    OPTIONS="$(grep '/var/lib/libvirt/images' /etc/fstab | awk '{print $4}' | cut -d, -f2-)"

    # Create the subvolume for /var/lib/libvirt/images
    if [[ -d "/var/lib/libvirt/images" ]] ; then
       sudo mv -v "/var/lib/libvirt/images" "/var/lib/libvirt/images-old"
       sudo btrfs subvolume create "/var/lib/libvirt/images"
       sudo cp -ar "/var/lib/libvirt/images-old/." "/var/lib/libvirt/images/"
    else
       sudo btrfs subvolume create "/var/lib/libvirt/images"
    fi
    sudo restorecon -RF "/var/lib/libvirt/images"
    printf "%-41s %-24s %-5s %-s %-s\n" \
       "UUID=${ROOT_UUID}" \
       "/var/lib/libvirt/images" \
       "btrfs" \
       "subvol=/var/lib/libvirt/images,${OPTIONS}" \
       "0 0" | \
       sudo tee -a /etc/fstab

    1. Madhu Desai Avatar

      I had no idea ChatGPT could do this as well. 😲😲

  18. alon Avatar
    alon

    also;

    sudo btrfs subvolume list /
    no any /var/lib/libvirt/images
    your script cannot create the sv for my side, others okay but this one.

    sudo chattr -R +C /var/lib/libvirt/images
    chattr: No such file or directory while trying to stat /var/lib/libvirt/images

    1. Madhu Desai Avatar

      I believe the directory /var/lib/libvirt/images is only created when 'Fedora Workstation' with GNOME is installed. So, before running the script, you should first create a directory:
      # mkdir -vp /var/lib/libvirt

  19. alon Avatar
    alon

    which partr differs for KDE? And I mostly use Brave + Vivaldi browsers which part should change?

    1. Madhu Desai Avatar

      For Brave:
      /home/$USER/.cache/BraveSoftware
      /home/$USER/.config/BraveSoftware

      For Vivaldi:
      /home/$USER/.config/vivaldi

      GNOME uses gdm (/var/lib/gdm). It's most likely sddm (/var/lib/sddm) for KDE. But I'm not certain. Please double-check.

  20. babs Avatar
    babs

    Why not enable timeline for home?

    1. Madhu Desai Avatar

      You certainly can. However, it is unnecessary. The idea is to always have a working snapshot available in case you mess up with the operating system (/), allowing you to roll back anytime. The /home directory, on the other hand, usually contains large files that take up a lot of space in snapshots. It is not advisable.

  21. Davide Avatar
    Davide

    When will you be able to publish the Fedora 38 with Snapshot and Rollback Support YouTube video?
    Thank you

    1. Madhu Desai Avatar

      I will in the next 2-3 days.

  22. Jonas Avatar
    Jonas

    Thanks a lot for your updated guide! The one with Luks also enabled is still coming?

    Thank you for your work!

    1. Madhu Desai Avatar

      Yes. I'll most likely post tomorrow. I've already completed the testing. Rather than using the Anaconda installer, this one will be installed in the terminal with 'dnf --installroot'.

Leave a Reply

Your email address will not be published. Required fields are marked *