Creating a Pop!_OS Recovery Partition by Hand

· Updated · 4 min read · Linux

This guide adds a recovery partition to an existing Pop!_OS install that was set up with a custom partition layout and therefore never got one. The partition holds a live copy of the operating system, so you can reinstall, upgrade or repair the system without USB media.

Written for Pop!_OS in February 2023, when 22.04 LTS was the current release. The steps have not been retested on later releases.

You need mkfs.vfat (the partition must be vfat), a partitioning tool (gparted, parted, gdisk or fdisk; I use gparted), pop-upgrade, which ships with Pop!_OS, and a text editor (I use vim). I assume you know the basics of partitions and filesystems, so I do not explain every step. Run most commands as root; sudo -i is the easiest way.

Creating the partition

You need 4.4 GiB of unallocated space on your main disk. It becomes a new FAT32 partition.

If you use btrfs, resize the filesystem before shrinking the storage underneath it: allocated chunks may sit in the area you are cutting away, so the data blocks have to be rebalanced. This command resizes the filesystem:

btrfs filesystem resize -4.4g /

I use gparted to resize the disk, but any partitioning tool works. Create a 4.4 GiB partition and a FAT32 filesystem on it. You will probably need to boot from installation media to do this; I do not remember for certain.

Format the partition as vfat (FAT32) and label it RECOVERY so it is easy to recognise later:

mkfs.vfat -n RECOVERY /dev/{{ partition }}

Mount it at /recovery:

mkdir /recovery

mount -L RECOVERY /recovery

Populating the partition

Installing the Pop!_OS ISO into the recovery partition uses the pop-upgrade tool. Its messages are cryptic when something goes wrong, so open a second terminal and follow the log:

journalctl -flu pop-upgrade

/tmp needs at least 2.5 GiB of free space, or the installation can fail.

In the first terminal, run as root:

pop-upgrade recovery upgrade from-release

A successful run looks like this:

root@pop-os:~# pop-upgrade recovery upgrade from-release
checking if pop-upgrade requires an update
Recovery event: fetching recovery files
Fetched 2493/2496 MiB
Recovery event: verifying checksum of fetched files
Recovery event: syncing recovery files with recovery partition
Recovery event: recovery partition upgrade completed
Recovery upgrade status: recovery partition refueled and ready to go

A successful run also adds an entry to /etc/fstab. If it is missing, add it by hand, and take care to use PARTUUID here, not UUID:

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
PARTUUID={{ pop_recovery_part_PARTUUID }} /recovery vfat umask=0077 0 0

If the run fails, disable the line that pop-upgrade created for /recovery in /etc/fstab.

Creating recovery.conf

Create /recovery/recovery.conf from this template. Again, mind the difference between UUID and PARTUUID:

HOSTNAME=pop-os
LANG=en_US.UTF-8
KBD_LAYOUT=us
KBD_MODEL=
KBD_VARIANT=
EFI_UUID=PARTUUID={{ pop_boot_part_PARTUUID }}
RECOVERY_UUID=PARTUUID={{ pop_recovery_part_PARTUUID }}
ROOT_UUID={{ pop_root_UUID }}
LUKS_UUID=
OEM_MODE=0

Replace every {{ }} placeholder with the UUID or PARTUUID indicated. blkid lists them:

root@pop-os:/recovery# blkid
/dev/vda3: UUID="6c5e552b-d98a-40a9-a00f-d2a1fe0a5beb" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="28ea30b3-783f-4ede-b1f2-82f5623a66ab"
/dev/mapper/cryptswap: LABEL="cryptswap" UUID="e6a5011e-84f4-4bdf-8d4b-f0b1dda61787" TYPE="swap"
/dev/zram0: UUID="2df20122-f063-4b01-ab91-e78dde3699d3" TYPE="swap"
/dev/vda4: UUID="b022ef26-84df-49d1-89d9-3e9f77a797f5" TYPE="swap" PARTUUID="dacd59bc-48a7-4db6-8c08-e32632deec56"
/dev/vda2: UUID="0E57-8003" BLOCK_SIZE="512" TYPE="vfat" PARTLABEL="recovery" PARTUUID="4c7e1e09-82b3-4209-bead-e269c82a37d9"
/dev/vda1: UUID="0E57-8F5C" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="b5518ef2-6974-415f-9b83-f3aabf36d612"

Based on that output, recovery.conf is filled in as follows:

HOSTNAME=pop-os
LANG=en_US.UTF-8
KBD_LAYOUT=us
KBD_MODEL=
KBD_VARIANT=
EFI_UUID=PARTUUID=b5518ef2-6974-415f-9b83-f3aabf36d612
RECOVERY_UUID=PARTUUID=4c7e1e09-82b3-4209-bead-e269c82a37d9
ROOT_UUID=6c5e552b-d98a-40a9-a00f-d2a1fe0a5beb
LUKS_UUID=
OEM_MODE=0

Adding the systemd-boot entry

As root, create a file in /boot/efi/loader/entries/ named Recovery-{{ pop_recovery_UUID }}.conf. The name is free; this one follows the convention of a default Pop!_OS install. With the example above the file is Recovery-0E57-8003.conf.

Template for the entry (UUID and PARTUUID again):

title Pop!_OS recovery
linux /EFI/Recovery-{{ recovery_partition_UUID }}/vmlinuz.efi
initrd /EFI/Recovery-{{ recovery_partition_UUID }}/initrd.gz
options boot=casper hostname=recovery userfullname=Recovery username=recovery live-media-path=/casper-{{ recovery_partition_UUID }} live-media=/dev/disk/by-partuuid/{{ recovery_partition_PARTUUID }} noprompt

I also recommend a two-second delay on the boot menu, which makes it easier to reach recovery mode when you need it:

root@pop-os:~# cd /boot/efi/loader/
root@pop-os:/boot/efi/loader# echo "timeout 2" >>loader.conf 
root@pop-os:/boot/efi/loader# cat loader.conf 
default Pop_OS-current
timeout 2

Reboot to test the new entry. If something went wrong during setup, the pop-upgrade journal logs are the first place to look.