Hibernate support on Ubuntu 20.04 with encrypted swap and encrypted root filesystem
So I installed Ubuntu 20.04 on my laptop with encrypted root filesystem with bcache support since I have a NVME SSD along with the usual hard disk in it. While setting up encrypted root filesystem the installer will not allow you to have unencrypted swap – and the default encrypted swap setup is to use a random encryption key that is changed at every boot – so that makes hibernation impossible. After a few shenanigans with the rescue system and systemd I managed to hibernate working with a fixed encryption key swap.
First thing is you have to set up fixed key encryption for the swap – so when using the installer to create an encrypted root filesystem – do not create a partition for swap, the installer will automatically create a swap in
/swapfile after installation. But when partitioning your disks leave out space equivalent to the size of your RAM in your SSD for creating our fixed key encrypted swap post installation.
After installation, disable existing swap using
sudo swapoff -a. Delete the entry of
/etc/fstab. Using your favorite partitioning tool – fdisk, gdisk, parted, or gparted, create a partition in your disk to hold the encrypted swap partition. In my case, the partition is
/dev/nvme0n1p3. Be careful in this step as you risk screwing up the installation itself.
Now we create a random key for encrypting the swap partition using
dd(1) and then use
cryptsetup(8) to create a luks header on the disk partition with the key:
dd if=/dev/urandom of=/.swap-key bs=1 count=512 cryptsetup luksFormat -d /.swap-key /dev/nvme0n1p3
It is a good idea to add a passphrase to the swap partition in case it has to be entered on console at any time – this is not exactly required but this helped me when I was playing around with the system – how would I enter a 512 byte random string on the console? 😀
cryptsetup luksAddKey -d /.swap-key /dev/nvme0n1p3
Open the encrypted partition and format it:
cryptsetup open -d /.swap-key /dev/nvme0n1p3 cryptswap mkswap /dev/mapper/cryptswap
If you note above the mapped name for the encrypted swap is named as
cryptswap – this name will be used later – you can change the name if you wish to. Add the
/etc/fstab entry so that the swap gets mounted at boot, also enable the swap at present:
echo /dev/mapper/cryptswap swap swap defaults 0 0 >> /etc/fstab swapon /dev/mapper/cryptswap
Next we have to populate
/etc/crypttab so that the initramfs can set up the swap partition and resume from hibernate. But before that, find the name of the device that is mounted as
/ (root filesystem) from
/etc/fstab. In my case that is
/dev/mapper/bcache0p1_crypt. Now we can create the
echo cryptswap UUID=$(blkid -s UUID -o value /dev/nvme0n1p3) /dev/disk/by-uuid/$(blkid -s UUID -o value /dev/mapper/bcache0p1_crypt):/.swap-key luks,discard,keyscript=/lib/cryptsetup/scripts/passdev,noauto >> /etc/crypttab
The first field in the
crypttab entry is mapped name of the device, second field is the UUID of the device which has this encrypted filesystem, the third field is path to the key file – here I have specified the path
/dev/disk/by-uuid/<UUID of ROOT FILESYSTEM>:/.swap-key. This syntax is documented in the
crypttab(5) man page for providing unlock keys – if you used a different path for the key then you have to change the path here as well. Important point to be noted here – we have put the encryption key of the swap inside encrypted root filesystem – so without unlocking the root filesystem it is not possible to access the key to the swap. Fourth field specifies the options for the encrypted device – you can omit discard in it if your swap partition is on a hard disk drive.
keyscript=/lib/cryptsetup/scripts/passdev script is documented at Debian Cryptsetup docs and
/usr/share/doc/cryptsetup-initramfs/README.initramfs.gz. It basically lets us use a key file stored on some device. The
noauto option is required to prevent systemd to try to mount the partition as systemd does not seem to support keyscript / fixed keys so when you boot the system normally you will end up without a swap partition because the systemd target fails – but with the
noauto option it gets mounted because initramfs unlocks the swap partition and then devices to be mounted are read from fstab.
Edit /etc/default/grub to disable the systemd crypto generator since we do not need it:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash luks=no"
Now update grub and initramfs, then test with a reboot that the swap is getting mounted during normal boot process:
update-grub update-initramfs -u -k all reboot
If successful, you can try hibernate – open some text editor window for example and type the following command – as there is no way to get the hibernate button in GNOME menu yet:
Once your machine turns off start it again and you should have the text editor back on the screen in the same state you had shut it down. Hibernate working! You can make this command as a keyboard shortcut in GNOME control center so you can hibernate with a key sequence.
Thank you so much for this guide! Worked great 🙂
One minor thing (probably a typo), I’m using 20.04.2, and `cryptsetup open -d /.swap-key cryptswap` didn’t work to open the drive.
It looks like the device name was also needed, this is what worked for me (using the same dev in this post):
`cryptsetup open -d /.swap-key /dev/nvme0n1p3 cryptswap`
Ah right, not sure how I missed that.
Thanks for fixing it! We all miss stuff my friend, but your guide was excellent!
Hope you and yours are well in these trying times.
LikeLiked by 1 person
Thanks a bunch for this guide. I am using it successfully in Ubuntu 22.04 (fresh install), the machine is now able to hibernate and wake-up from hibernation using encrypted swap. However, I noticed a problem, on occasion, after hibernation, the root filesystem comes back up as read-only, and once, the resume got interrupted and I got the dreaded “initramfs” busybox environment, where luckily I could run fsck on the root filesystem encrypted disk that was reporting errors (after fsck, everything worked OK. The disk itself seems fine, it’s a new NVME disk – I ran multiple smartctl tests and all show zero errors, the smartctl logs show zero errors etc.
Did you ever notice this problem? any recommendation?
LikeLiked by 1 person
What FS are you using for the root FS and any specific mounting options?
Seems like something to do with the write caching.
Try running drop buffers and/or sync command before hibernate to see if that solves the problem
I am using ext4, the encrypted root disk was created by the installer,
dev/mapper/nvme0n1p4_crypt / ext4 errors=remount-ro 0 1
nvme0n1p4_crypt UUID=[…………….] none luks,discard
I believe found a solution for 22.04’s resume issues, I believe they were related to nvidia/kernel interaction issues and not related to the encryption of the system disk. Here’s what I’m using that seems to work:
Workaround for resume: to prevent occasional (typically after “long” hibernations) read-only mount of the system partition and forced fsck during initram:
* Use Nvidia driver 470 series instead of 510 (due issues with either keyboard or mouse not working on resume)
* Follow the ‘workaround’: https://askubuntu.com/questions/1032633/18-04-screen-remains-blank-after-wake-up-from-suspend/1391917#1391917 (disable nvidia suspend/hibernate/resume systemd services to force the old method of nvidia hibernation)
Awesome! Nvidia drivers can exhibit unexpected behavior at times.
Well after more testing, the readonly-filesystem on resume issue came up again. Seems to be related to his discussion here: https://bbs.archlinux.org/viewtopic.php?id=249962
And the solution (workaround) to this is to go with a swapfile in the encrypted root partition. These days there seems to be zero performance penalties to using swapfiles. This also adds some flexibility when upgrading/moving the disk to a larger system. Time to update the older practice of using dedicated partitions for swap, I guess
Swapfiles would be part of the journaling stuff that’s done by the filesystem used to store OS/data files. My personal preference would be to have a swap partition to avoid unnecessary IO due to journaling, but if there’s no way then swapfile it is.
While I used the setup I described in the post, I didn’t experience FS corruption, may be something to do with the kernel and/or initramfs tools versions.