automated-local.rst 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. .. include:: ../global.rst.inc
  2. .. highlight:: none
  3. Automated backups to a local hard drive
  4. =======================================
  5. This guide shows how to automate backups to a hard drive directly connected
  6. to your computer. If a backup hard drive is connected, backups are automatically
  7. started, and the drive shut-down and disconnected when they are done.
  8. This guide is written for a Linux-based operating system and makes use of
  9. systemd and udev.
  10. Overview
  11. --------
  12. An udev rule is created to trigger on the addition of block devices. The rule contains a tag
  13. that triggers systemd to start a oneshot service. The oneshot service executes a script in
  14. the standard systemd service environment, which automatically captures stdout/stderr and
  15. logs it to the journal.
  16. The script mounts the added block device, if it is a registered backup drive, and creates
  17. backups on it. When done, it optionally unmounts the file system and spins the drive down,
  18. so that it may be physically disconnected.
  19. Configuring the system
  20. ----------------------
  21. First, create the ``/etc/backups`` directory (as root).
  22. All configuration goes into this directory.
  23. Find out the ID of the partition table of your backup disk (here assumed to be /dev/sdz):
  24. lsblk --fs -o +PTUUID /dev/sdz
  25. Then, create ``/etc/backups/40-backup.rules`` with the following content (all on one line)::
  26. ACTION=="add", SUBSYSTEM=="block", ENV{ID_PART_TABLE_UUID}=="<the PTUUID you just noted>", TAG+="systemd", ENV{SYSTEMD_WANTS}="automatic-backup.service"
  27. The "systemd" tag in conjunction with the SYSTEMD_WANTS environment variable has systemd
  28. launch the "automatic-backup" service, which we will create next, as the
  29. ``/etc/backups/automatic-backup.service`` file:
  30. .. code-block:: ini
  31. [Service]
  32. Type=oneshot
  33. ExecStart=/etc/backups/run.sh
  34. Now, create the main backup script, ``/etc/backups/run.sh``. Below is a template,
  35. modify it to suit your needs (e.g. more backup sets, dumping databases etc.).
  36. .. code-block:: bash
  37. #!/bin/bash -ue
  38. # The udev rule is not terribly accurate and may trigger our service before
  39. # the kernel has finished probing partitions. Sleep for a bit to ensure
  40. # the kernel is done.
  41. #
  42. # This can be avoided by using a more precise udev rule, e.g. matching
  43. # a specific hardware path and partition.
  44. sleep 5
  45. #
  46. # Script configuration
  47. #
  48. # The backup partition is mounted there
  49. MOUNTPOINT=/mnt/backup
  50. # This is the location of the Borg repository
  51. TARGET=$MOUNTPOINT/borg-backups/backup.borg
  52. # Archive name schema
  53. DATE=$(date --iso-8601)-$(hostname)
  54. # This is the file that will later contain UUIDs of registered backup drives
  55. DISKS=/etc/backups/backup.disks
  56. # Find whether the connected block device is a backup drive
  57. for uuid in $(lsblk --noheadings --list --output uuid)
  58. do
  59. if grep --quiet --fixed-strings $uuid $DISKS; then
  60. break
  61. fi
  62. uuid=
  63. done
  64. if [ ! $uuid ]; then
  65. echo "No backup disk found, exiting"
  66. exit 0
  67. fi
  68. echo "Disk $uuid is a backup disk"
  69. partition_path=/dev/disk/by-uuid/$uuid
  70. # Mount file system if not already done. This assumes that if something is already
  71. # mounted at $MOUNTPOINT, it is the backup drive. It won't find the drive if
  72. # it was mounted somewhere else.
  73. findmnt $MOUNTPOINT >/dev/null || mount $partition_path $MOUNTPOINT
  74. drive=$(lsblk --inverse --noheadings --list --paths --output name $partition_path | head --lines 1)
  75. echo "Drive path: $drive"
  76. #
  77. # Create backups
  78. #
  79. # Options for borg create
  80. BORG_OPTS="--stats --one-file-system --compression lz4 --checkpoint-interval 86400"
  81. # Set BORG_PASSPHRASE or BORG_PASSCOMMAND somewhere around here, using export,
  82. # if encryption is used.
  83. # No one can answer if Borg asks these questions, it is better to just fail quickly
  84. # instead of hanging.
  85. export BORG_RELOCATED_REPO_ACCESS_IS_OK=no
  86. export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=no
  87. # Log Borg version
  88. borg --version
  89. echo "Starting backup for $DATE"
  90. # This is just an example, change it however you see fit
  91. borg create $BORG_OPTS \
  92. --exclude root/.cache \
  93. --exclude var/lib/docker/devicemapper \
  94. $TARGET::$DATE-$$-system \
  95. / /boot
  96. # /home is often a separate partition / file system.
  97. # Even if it isn't (add --exclude /home above), it probably makes sense
  98. # to have /home in a separate archive.
  99. borg create $BORG_OPTS \
  100. --exclude 'sh:home/*/.cache' \
  101. $TARGET::$DATE-$$-home \
  102. /home/
  103. echo "Completed backup for $DATE"
  104. # Just to be completely paranoid
  105. sync
  106. if [ -f /etc/backups/autoeject ]; then
  107. umount $MOUNTPOINT
  108. hdparm -Y $drive
  109. fi
  110. if [ -f /etc/backups/backup-suspend ]; then
  111. systemctl suspend
  112. fi
  113. Create the ``/etc/backups/autoeject`` file to have the script automatically eject the drive
  114. after creating the backup. Rename the file to something else (e.g. ``/etc/backup/autoeject-no``)
  115. when you want to do something with the drive after creating backups (e.g running check).
  116. Create the ``/etc/backups/backup-suspend`` file if the machine should suspend after completing
  117. the backup. Don't forget to disconnect the device physically before resuming,
  118. otherwise you'll enter a cycle. You can also add an option to power down instead.
  119. Create an empty ``/etc/backups/backup.disks`` file, you'll register your backup drives
  120. there.
  121. The last part is actually to enable the udev rules and services:
  122. .. code-block:: bash
  123. ln -s /etc/backups/40-backup.rules /etc/udev/rules.d/40-backup.rules
  124. ln -s /etc/backups/automatic-backup.service /etc/systemd/system/automatic-backup.service
  125. systemctl daemon-reload
  126. udevadm control --reload
  127. Adding backup hard drives
  128. -------------------------
  129. Connect your backup hard drive. Format it, if not done already.
  130. Find the UUID of the file system that backups should be stored on::
  131. lsblk -o+uuid,label
  132. Note the UUID into the ``/etc/backup/backup.disks`` file.
  133. Mount the drive to /mnt/backup.
  134. Initialize a Borg repository at the location indicated by ``TARGET``::
  135. borg init --encryption ... /mnt/backup/borg-backups/backup.borg
  136. Unmount and reconnect the drive, or manually start the ``automatic-backup`` service
  137. to start the first backup::
  138. systemctl start --no-block automatic-backup
  139. See backup logs using journalctl::
  140. journalctl -fu automatic-backup [-n number-of-lines]
  141. Security considerations
  142. -----------------------
  143. The script as shown above will mount any file system with an UUID listed in
  144. ``/etc/backup/backup.disks``. The UUID check is a safety / annoyance-reduction
  145. mechanism to keep the script from blowing up whenever a random USB thumb drive is connected.
  146. It is not meant as a security mechanism. Mounting file systems and reading repository
  147. data exposes additional attack surfaces (kernel file system drivers,
  148. possibly user space services and Borg itself). On the other hand, someone
  149. standing right next to your computer can attempt a lot of attacks, most of which
  150. are easier to do than e.g. exploiting file systems (installing a physical key logger,
  151. DMA attacks, stealing the machine, ...).
  152. Borg ensures that backups are not created on random drives that "just happen"
  153. to contain a Borg repository. If an unknown unencrypted repository is encountered,
  154. then the script aborts (BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=no).
  155. Backups are only created on hard drives that contain a Borg repository that is
  156. either known (by ID) to your machine or you are using encryption and the
  157. passphrase of the repository has to match the passphrase supplied to Borg.