Warning: Most of what is done here in this tutorial is now already implemented inside calamares installer!
but … it can be useful for pure arch install…
warning added by joekamprad 21.5.2022
Inspired by some posts from @TomZ I decided to have a (re-)go at btrfs, test its snapshot capabilities and the ease of restoring these, try different subvolume setups and check if calamares allows for an encrypted install.
As a result I have decided to make the following my new default type of install:
- BTRFSonLUKS (fully LUKS encrypted single partition containing a btrfs filesystem with /boot, /‘root’ and /home)
- /, /home, swapfile, pkg cache as separate subvolumes; to allow easy snapshotting of root system
- automated creation of snapshots (on system upgrade & daily & boot)
- ability to boot into a working snapshot from the grub menu (automated creation of boot entries) and then setting this or other snapshot as new default system (from GUI)
- swapfile, with the ability to hibernate
With this low-maintenance type of setup it should be possible to recover/rollback from a problematic upgrade by simply booting into a working snapshot (these snapshots are created automatically) and setting this as the new default from within the booted system. You could then just wait a couple of days and then check if the upgrade problems still persist. Most of the time the problem will be fixed. (= Newb friendly ) Note that the creation or restore of a snapshot takes about a second!
The following is a tutorial on setting up this type of system with the help of calamares and a little cli.
+++ QUICK (copy and paste) VERSION ++++++++++++++++++++++++++++++++
(Tested with endeavouros-2019.12.22-x86_64.iso
)
The provided cli commands can be copied and pasted/run in bulk, adding only a couple of minutes to your normal install time. If you really need to know more, I have provided a step-by-step explanation of the used commands in the “lengthy version” below.
#01 - Boot into Live-CD environment & set up partitions
With the help of GParted
, assuming you have an empty disk …
- create a GPT partition table
- create sda1 with 300 to 512MiB, format as fat32 and set boot & esp flag
- leave rest unallocated
+------------+-------------+-------------+
| 300-512MiB | rest xGiB |
| boot & esp | unallocated |
| flag set | |
| /dev/sda1 | |
+------------+-------------+-------------+
With other storage type, dev/sda1 could also be called /dev/nvme0n1p1; in this case just substitute sda1 with nvme0n1p1.
#02 - Change default btrfs calamares settings for fstab
Open a Terminal
and type (or mark and copy with ctrl-c and paste in terminal with shift-ctrl-v | you can copy&paste all the lines at once) …
sudo sed -i 's/compress=lzo/compress=zstd/' /usr/share/calamares/modules/fstab.conf sudo sed -i 's/autodefrag/autodefrag,compress=zstd/' /usr/share/calamares/modules/fstab.conf
#03 - Install system with calamares
(off- or online install)
Set up calamares like you usually would (Location, Keyboard, Users, …) but
choose Manual partioning
and edit (double-click the partition(s) in the list view) …
- /dev/sda1
- Mount point → /boot/efi
- set boot flag
- keep fat32
- free space
- Mount point → /
- File system → btrfs
- Encrypt: choose a secure password
Let Calamares finish the installation. If you get a warning about missing esp or boot flag(s) on /dev/sda1 just add them with GParted and continue with the install.
After install, do NOT check the “Restart now” checkbox.
#04 - Choose your swapfile size
e. g. “8G” or “8192M”
swapsize=8G
#05 - Run the following (just copy&paste all the lines at once)
sudo mkdir /mnt/btrfs btrfsonluks=`sudo blkid -o device | grep luks` sudo mount -o subvolid=5 $btrfsonluks /mnt/btrfs sudo sed -i 's/compress=zstd 0 1/compress=zstd 0 0/' /mnt/btrfs/@/etc/fstab sudo sed -i 's/compress=zstd 0 2/compress=zstd 0 0/' /mnt/btrfs/@/etc/fstab sudo btrfs subvolume create /mnt/btrfs/@var-cache-pacman-pkg fstabstr=`grep "/home" /mnt/btrfs/@/etc/fstab` fstabstr=${fstabstr//\/home/\/var\/cache\/pacman\/pkg} fstabstr=${fstabstr//@home/@var-cache-pacman-pkg} sudo sh -c "echo $fstabstr >> /mnt/btrfs/@/etc/fstab" sudo btrfs subvolume create /mnt/btrfs/@swap sudo mkdir /mnt/btrfs/@/swap sudo sh -c "printf '\n$btrfsonluks /swap btrfs subvol=@swap,defaults,compress=no 0 0\n' >> /mnt/btrfs/@/etc/fstab" sudo truncate -s 0 /mnt/btrfs/@swap/swapfile sudo chattr +C /mnt/btrfs/@swap/swapfile sudo btrfs property set /mnt/btrfs/@swap/swapfile compression none sudo fallocate -l $swapsize /mnt/btrfs/@swap/swapfile sudo chmod 600 /mnt/btrfs/@swap/swapfile sudo mkswap /mnt/btrfs/@swap/swapfile sudo swapon /mnt/btrfs/@swap/swapfile sudo sh -c "echo '/swap/swapfile none swap defaults 0 0' >> /mnt/btrfs/@/etc/fstab" wget https://raw.githubusercontent.com/osandov/osandov-linux/master/scripts/btrfs_map_physical.c gcc -O2 -o btrfs_map_physical btrfs_map_physical.c offset=`sudo ./btrfs_map_physical /mnt/btrfs/@swap/swapfile` offset_arr=(`echo ${offset}`) offset_pagesize=(`getconf PAGESIZE`) offset=$(( offset_arr[25] / offset_pagesize )) sudo sed -i "s/loglevel=3/loglevel=3 resume_offset=$offset/" /mnt/btrfs/@/etc/default/grub sudo sed -i 's/keymap encrypt filesystems/keymap encrypt filesystems resume/' /mnt/btrfs/@/etc/mkinitcpio.conf sudo mkdir /mnt/chroot sudo mount -o compress=zstd,subvol=@ $btrfsonluks /mnt/chroot efidevice=`sudo blkid -o device -l -t TYPE=vfat` sudo mount $efidevice /mnt/chroot/boot/efi sudo arch-chroot /mnt/chroot sudo pacman --noconfirm -S cronie sudo systemctl enable cronie.service sudo grub-mkconfig -o /boot/grub/grub.cfg sudo mkinitcpio -p linux
#06 - REBOOT into your new system & run the following …
sudo pacman --noconfirm -Syy && yay --noconfirm -S timeshift timeshift-autosnap grub-btrfs
Then run …
sudo cp /etc/default/timeshift.json /etc/timeshift.json && fs_uuid=`sudo blkid -o device | grep luks` && fs_uuid=`sudo blkid -o value -s UUID $fs_uuid` && sudo sed -i "s/backup_device_uuid\" : \"/backup_device_uuid\" : \"$fs_uuid/" /etc/timeshift.json && fs_uuid=`sudo blkid -o device -l -t TYPE=crypto_LUKS` && fs_uuid=`sudo blkid -o value -s UUID $fs_uuid` && sudo sed -i "s/parent_device_uuid\" : \"/parent_device_uuid\" : \"$fs_uuid/" /etc/timeshift.json && sudo sed -i 's/run" : "true/run" : "false/' /etc/timeshift.json && sudo sed -i 's/btrfs_mode" : "false/btrfs_mode" : "true/' /etc/timeshift.json && sudo sed -i 's/ "include_btrfs_home" : "false",/ "include_btrfs_home_for_backup" : "false",\n "include_btrfs_home_for_restore" : "false",/' /etc/timeshift.json && sudo sed -i 's/schedule_daily" : "false/schedule_daily" : "true/' /etc/timeshift.json && sudo sed -i 's/schedule_boot" : "false/schedule_boot" : "true/' /etc/timeshift.json && sudo sed -i 's/count_boot" : "5/count_boot" : "3/' /etc/timeshift.json
Choose the amount of maximum snapshots your system will allow and keep.
Timeshift cleans the automatically created snapshots but the ones you create manually aren’t handled by Timeshift and would be kept indefinetily. Just choose a high number if you prefer to delete these manually and not let the system only keep the newest (e. g.) 13 snapshots.
max_snapshots=13
Then execute …
sudo sh -c ' cat > /etc/systemd/system/limit-timeshift-snapshots-update-grub.service <<- "EOF" [Unit] Description=Keep only latest max_snapshots timeshift snapshots and update grub.cfg before shutdown Before=poweroff.target [Service] Type=oneshot RemainAfterExit=yes ExecStart=/bin/true ExecStop= [Install] WantedBy=multi-user.target EOF ' && sudo sed -i "s#max_snapshots#$max_snapshots#" /etc/systemd/system/limit-timeshift-snapshots-update-grub.service && sudo sed -i "s#ExecStop=#ExecStop=/usr/bin/sh -c \"cd /run/timeshift/backup/timeshift-btrfs/snapshots/ \&\& rm -rf \`ls -1r | awk 'NR>$max_snapshots'\` \&\& /usr/bin/grub-mkconfig -o /boot/grub/grub.cfg\"#" /etc/systemd/system/limit-timeshift-snapshots-update-grub.service && sudo systemctl enable limit-timeshift-snapshots-update-grub.service && sudo systemctl start limit-timeshift-snapshots-update-grub.service && sudo timeshift --create --comments "1st"
#07 - OPTIONAL: to create some desktop shortcuts (to Timeshift, manually create a snapshot and hibernate) run the following …
(Note: to get rid of these later on just delete the shortcuts from your desktop)
sh -c ' cat > ~/Desktop/timeshift-gtk.desktop <<- "EOF" [Desktop Entry] Name=Timeshift MimeType= Exec=timeshift-launcher Type=Application GenericName=System Restore Utility Terminal=false Icon=timeshift Comment=System Restore Utility X-KDE-StartupNotify=false Categories=System; X-GNOME-UsesNotifications=true EOF chmod +x ~/Desktop/timeshift-gtk.desktop ' sh -c ' cat > ~/Desktop/create_snapshot.desktop <<- "EOF" [Desktop Entry] Name=Create Snapshot Comment=Create btrfs snapshot of root Exec= Icon=timeshift StartupNotify=false Terminal=true Type=Application EOF ' sed -i "s#Exec=#Exec=sudo sh -c \'timeshift --create --comments \"manual\" \&\& sleep 2\'#" ~/Desktop/create_snapshot.desktop chmod +x ~/Desktop/create_snapshot.desktop sh -c ' cat > ~/Desktop/hibernate_alt.desktop <<- "EOF" [Desktop Entry] Name=Hibernate Comment=Hibernate (alternative method) Exec= Icon=system-shutdown StartupNotify=false Terminal=true Type=Application EOF ' sed -i "s#Exec=#Exec=sudo sh -c \'echo disk > /sys/power/state\'#" ~/Desktop/hibernate_alt.desktop chmod +x ~/Desktop/hibernate_alt.desktop
DONE! You should now have a fully encrypted system with the ability to rollback to automatically (and manually) created snapshots and be able to hibernate.
Note that this setup isn’t meant to be a backup strategy replacement! The snapshots are stored on the same disk as your system; if this fails the snapshots won’t be accessible. At least your /home subvolume should be backuped to another physical device. So, just apply your normal backup strategy of choice.
# - How to RESTORE a snapshot (previous system state)
A - If you ever need to reset your system to a stored state, just
- Launch
Timeshift
from the menu (or desktop shortcut) - Select a snapshot and hit restore
- Reboot
That’s all. Takes mere seconds and doesn’t get any easier.
BTW, you could also restore a snapshot from the cli!
B - In case you can’t boot into your desktop environment try to
- Boot directly into a snapshot from the GRUB (boot) menu
- see A (above) …
C - In case you need to restore a snapshot from a live system (e. g. EndeavourOS Install medium)
- Boot into the live environment
- Install Timeshift into the live environment; run
sudo pacman --noconfirm -Syy cronie yay --noconfirm -S timeshift
- see A (above) …
D - In case you need to chroot
from a live system (e. g. EndeavourOS Install medium)
- Boot into the live environment
- Decrypt and mount your luks partition (e. g. /dev/sda2)
sudo cryptsetup luksOpen /dev/sda2 crypt && sudo mount -o compress=zstd,subvol=@ /dev/mapper/crypt /mnt
- Mount your EFI boot folder (e. g. /dev/sda1)
sudo mount /dev/sda1 /mnt/boot/efi
chroot
into your system
sudo arch-chroot /mnt
- Do some root stuff …
[Edit: changed “ls -t” to “ls -1r” in step #06
Because Timeshift regularly changes the modification date of all snapshots, listing by date to find the oldest snapshots didn’t work as expected. So we now list by file name, which contains the snapshot date.]
[Edit 2020-03-20: changed the path “/mnt/timeshift/backup/…” to “/run/timeshift/backup/…” in step #06
It seems that Timeshift mounts its snapshots under /run/timeshift/… . This wasn’t the case on my initial test system but two newer installs point to /run so this seems to be the (new?) timeshift behaviour.]