Backup on LUKS-encrypted external HDD

One of my strategies to prevent important (electronic-form) information from becoming too ephemeral… [Script] [Config] #backups #rsync #luks #usb #drive [Update history]

The goal of this text is to share with you a simple strategy to backup your important data to an encrypted external drive. (LUKS, which stands for Linux Unified Key Setup, is the disk encryption framework that we will use to encrypt the external drive.)

Scenario. More specifically, the goal is to create a backup of a set of locations—say, /home/<user>/folder1, /home/<user>/folder_2, etc.—where <user> is your username. The bash script I will provide also gives you the possibility of quickly restoring that external backup onto your computer—on which more later.

Prerequisites. An external hard drive, of course, and in addition, a machine with a Linux installation that isn’t ancient. As already hinted above, the bash shell is required, and furthermore, the cryptsetup package is also a requirement (this is what we’ll actually use to create and manage the LUKS encrypted volume). Finally, the user which will do the backups must have sudo privileges.

To avoid the perilous path of partioning, I shall assume that your entire external drive is to be formatted as a LUKS container. This, of course, needn’t be so: it is perfectly feasible to create multiple partions in said external drive, and use just one of them as a LUKS container for your backups. But I am afraid that you must look elsewhere for instructions on how to do that.1

Hereinafter, I shall assume that your external drive is /dev/sdb—modify as required for your own system. The first step, as I said, is to turn your whole drive into a LUKS container. But before that, there is an

IMPORTANT CAVEAT: if your drive has some previous data in it, setting it up as a LUKS container will render any such data inaccessible. But, just to make matters worse, it might not actually delete said pre-existing data. So, on the one hand, please backup any previous data that you want to keep. On the other hand, do not assume that the format process will wipe the drive of its previous contents.2

Setup. LUKS encryption can be done either using a passphrase, or a key file—here we are going for the latter. The key file it self can be anything really—an image, a PDF file, etc.—but here, we are going for a randomly generated hunk of bits (note that this has to be done as root):

# dd bs=512 count=4 if=/dev/random of=/path/to/keyfile iflag=fullblock

Needless to say, anyone who gets access to this file (keyfile), can trivially decrypt the LUKS container to be created—so be sure to keep it safe!! It is already owned by root, but just for good measure, I also make sure that only root can read it:3

# chmod 400 /path/to/keyfile

Now, to format the drive as a LUKS container, do:

# cryptsetup luksFormat /dev/sdb /path/to/keyfile

Now we have to open the encrypted volume we just created, and format that with an actual file system. Here I will use ext4, even despite its annoying lost+found folder.4

# cryptsetup --key-file=/path/to/file open /dev/sdb backupdev

This creates a new (“virtual”) device under /dev/mapper, more specifically /dev/mapper/backupdev. To dump an ext4 file system on it:

# mkfs.ext4 /dev/mapper/backupdev

And now mount it:

# mount /dev/mapper/backupdev /mnt

By default, the owner of your new partion will be root—which will mean that any copying of files therein must also be done as root. To avoid this, change its owner to you:5

# chown -R <user> /mnt

Moving on, you can choose to store the backup data directly into the root of your drive (i.e., its top folder), but I prefer to create a specific folder, and name it something like <USER>-BACKUP. Then, all of your backup data will be inside that folder. This leaves you free to, for example, use any remaining space on your drive to store other things. It is done like so:

# mkdir /mnt/<USER>-BACKUP

The setup of the external drive is done! All that is left is to unmount it, close the encrypted container—and then proceed to setup the bash script. (Note that below, umount is not a typo—the command really is named like that…)

# umount /mnt
# cryptsetup close backupdev

OK, onto the script! The code is fairly simple: it consists of the script proper, and its configuration file. Save the former into a file with the .sh extension (below I will use backup_script.sh), and the latter in file $HOME/.config/ext_luks_bck/config.sh.6

On the config file, there are the following variables to set up:

Usage. Just run the script:7

$ sh /path/to/backup_script.sh

Without any arguments, as shown above, it creates/syncs a backup. With -r, it restores the data in the backup to its original location—but without overwriting files that, while present in the backup, have been modified (in the original location) after the backup was done. I.e., restoring a backup preserves files that are newer than the version that exists in the backup.8

In either case, adding the -y option does a --dry-run (i.e., a simulation) of the task that would have been done, if the -y had not been given. (So giving -y alone simulates a backup; giving -y -r—the order does not matter—simulates restoring a backup.)

March 8, 2022. Got feedback? Great, email is your friend!

*   *   *

Update history

March 21, 2024. Script can now be used with a user-specified config file $ sh /path/to/backup_script.sh -f /path/to/custom/config/file.sh. I also added the ability to exclude certain files or folders from being backed up; cf. the new config template.

August 31, 2023. The script now outputs messages to inform the user when the LUKS volume has been successfully mounted/unmounted. Moreover, two new options: -m mounts the LUKS volume, and nothing else; and -u unmounts the LUKS volume, and nothing else. Also, the configuration variables have been placed in a separate file, to ease setting them up.