| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 | .. include:: ../global.rst.inc.. highlight:: noneAutomated backups to a local hard drive=======================================This guide shows how to automate backups to a hard drive directly connectedto your computer. If a backup hard drive is connected, backups are automaticallystarted, and the drive shut-down and disconnected when they are done.This guide is written for a Linux-based operating system and makes use ofsystemd and udev.Overview--------A udev rule is created to trigger on the addition of block devices. The rule contains a tagthat triggers systemd to start a one-shot service. The one-shot service executes a script inthe standard systemd service environment, which automatically captures stdout/stderr andlogs it to the journal.The script mounts the added block device if it is a registered backup drive and createsbackups on it. When done, it optionally unmounts the filesystem and spins the drive down,so that it may be physically disconnected.Configuring the system----------------------First, create the ``/etc/backups`` directory (as root).All configuration goes into this directory.Find out the ID of the partition table of your backup disk (here assumed to be /dev/sdz)::    lsblk --fs -o +PTUUID /dev/sdzThen, create ``/etc/backups/80-backup.rules`` with the following content (all on one line)::    ACTION=="add", SUBSYSTEM=="block", ENV{ID_PART_TABLE_UUID}=="<the PTUUID you just noted>", TAG+="systemd", ENV{SYSTEMD_WANTS}+="automatic-backup.service"The "systemd" tag in conjunction with the SYSTEMD_WANTS environment variable has systemdlaunch the "automatic-backup" service, which we will create next, as the``/etc/backups/automatic-backup.service`` file:.. code-block:: ini    [Service]    Type=oneshot    ExecStart=/etc/backups/run.shNow, create the main backup script, ``/etc/backups/run.sh``. Below is a template;modify it to suit your needs (e.g., more backup sets, dumping databases, etc.)... code-block:: bash    #!/bin/bash -ue    # The udev rule is not terribly accurate and may trigger our service before    # the kernel has finished probing partitions. Sleep for a bit to ensure    # the kernel is done.    #    # This can be avoided by using a more precise udev rule, e.g. matching    # a specific hardware path and partition.    sleep 5    #    # Script configuration    #    # The backup partition is mounted there    MOUNTPOINT=/mnt/backup    # This is the location of the Borg repository    TARGET=$MOUNTPOINT/borg-backups/backup.borg    # Archive name schema    DATE=$(date --iso-8601)-$(hostname)    # This is the file that will later contain UUIDs of registered backup drives    DISKS=/etc/backups/backup.disks    # Find whether the connected block device is a backup drive    for uuid in $(lsblk --noheadings --list --output uuid)    do            if grep --quiet --fixed-strings $uuid $DISKS; then                    break            fi            uuid=    done    if [ ! $uuid ]; then            echo "No backup disk found, exiting"            exit 0    fi    echo "Disk $uuid is a backup disk"    partition_path=/dev/disk/by-uuid/$uuid    # Mount filesystem if not already done. This assumes that if something is already    # mounted at $MOUNTPOINT, it is the backup drive. It will not find the drive if    # it was mounted somewhere else.    findmnt $MOUNTPOINT >/dev/null || mount $partition_path $MOUNTPOINT    drive=$(lsblk --inverse --noheadings --list --paths --output name $partition_path | head --lines 1)    echo "Drive path: $drive"    #    # Create backups    #    # Options for borg create    BORG_OPTS="--stats --one-file-system --compression lz4"    # Set BORG_PASSPHRASE or BORG_PASSCOMMAND somewhere around here, using export,    # if encryption is used.    # Because no one can answer these questions non-interactively, it is better to    # fail quickly instead of hanging.    export BORG_RELOCATED_REPO_ACCESS_IS_OK=no    export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=no    # Log Borg version    borg --version    echo "Starting backup for $DATE"    # This is just an example, change it however you see fit    borg create $BORG_OPTS \      --exclude root/.cache \      --exclude var/lib/docker/devicemapper \      $TARGET::$DATE-$$-system \      / /boot    # /home is often a separate partition/filesystem.    # Even if it is not (add --exclude /home above), it probably makes sense    # to have /home in a separate archive.    borg create $BORG_OPTS \      --exclude 'sh:home/*/.cache' \      $TARGET::$DATE-$$-home \      /home/    echo "Completed backup for $DATE"    # Just to be completely paranoid    sync    if [ -f /etc/backups/autoeject ]; then            umount $MOUNTPOINT            hdparm -Y $drive    fi    if [ -f /etc/backups/backup-suspend ]; then            systemctl suspend    fiCreate the ``/etc/backups/autoeject`` file to have the script automatically eject the driveafter creating the backup. Rename the file to something else (e.g., ``/etc/backups/autoeject-no``)when you want to do something with the drive after creating backups (e.g., running checks).Create the ``/etc/backups/backup-suspend`` file if the machine should suspend after completingthe backup. Don't forget to disconnect the device physically before resuming,otherwise you'll enter a cycle. You can also add an option to power down instead.Create an empty ``/etc/backups/backup.disks`` file, in which you will register your backup drives.Finally, enable the udev rules and services:.. code-block:: bash    ln -s /etc/backups/80-backup.rules /etc/udev/rules.d/80-backup.rules    ln -s /etc/backups/automatic-backup.service /etc/systemd/system/automatic-backup.service    systemctl daemon-reload    udevadm control --reloadAdding backup hard drives-------------------------Connect your backup hard drive. Format it, if not done already.Find the UUID of the filesystem on which backups should be stored::    lsblk -o+uuid,labelRecord the UUID in the ``/etc/backups/backup.disks`` file.Mount the drive at /mnt/backup.Initialize a Borg repository at the location indicated by ``TARGET``::    borg init --encryption ... /mnt/backup/borg-backups/backup.borgUnmount and reconnect the drive, or manually start the ``automatic-backup`` serviceto start the first backup::    systemctl start --no-block automatic-backupSee backup logs using journalctl::    journalctl -fu automatic-backup [-n number-of-lines]Security considerations-----------------------The script as shown above will mount any filesystem with a UUID listed in``/etc/backups/backup.disks``. The UUID check is a safety/annoyance-reductionmechanism to keep the script from blowing up whenever a random USB thumb drive is connected.It is not meant as a security mechanism. Mounting filesystems and reading repositorydata exposes additional attack surfaces (kernel filesystem drivers,possibly userspace services, and Borg itself). On the other hand, someonestanding right next to your computer can attempt a lot of attacks, most of whichare easier to do than, e.g., exploiting filesystems (installing a physical keylogger,DMA attacks, stealing the machine, ...).Borg ensures that backups are not created on random drives that "just happen"to contain a Borg repository. If an unknown unencrypted repository is encountered,then the script aborts (BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=no).Backups are only created on hard drives that contain a Borg repository that iseither known (by ID) to your machine or you are using encryption and thepassphrase of the repository has to match the passphrase supplied to Borg.
 |