automated-local.rst 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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. Then, create ``/etc/backups/40-backup.rules`` with the following content (all on one line)::
  24. ACTION=="add", SUBSYSTEM=="bdi", DEVPATH=="/devices/virtual/bdi/*",
  25. TAG+="systemd", ENV{SYSTEMD_WANTS}="automatic-backup.service"
  26. .. topic:: Finding a more precise udev rule
  27. If you always connect the drive(s) to the same physical hardware path, e.g. the same
  28. eSATA port, then you can make a more precise udev rule.
  29. Execute ``udevadm monitor`` and connect a drive to the port you intend to use.
  30. You should see a flurry of events, find those regarding the `block` subsystem.
  31. Pick the event whose device path ends in something similar to a device file name,
  32. typically`sdX/sdXY`. Use the event's device path and replace `sdX/sdXY` after the
  33. `/block/` part in the path with a star (\*). For example:
  34. `DEVPATH=="/devices/pci0000:00/0000:00:11.0/ata3/host2/target2:0:0/2:0:0:0/block/*"`.
  35. Reboot a few times to ensure that the hardware path does not change: on some motherboards
  36. components of it can be random. In these cases you cannot use a more accurate rule,
  37. or need to insert additional stars for matching the path.
  38. The "systemd" tag in conjunction with the SYSTEMD_WANTS environment variable has systemd
  39. launch the "automatic-backup" service, which we will create next, as the
  40. ``/etc/backups/automatic-backup.service`` file:
  41. .. code-block:: ini
  42. [Service]
  43. Type=oneshot
  44. ExecStart=/etc/backups/run.sh
  45. Now, create the main backup script, ``/etc/backups/run.sh``. Below is a template,
  46. modify it to suit your needs (e.g. more backup sets, dumping databases etc.).
  47. .. code-block:: bash
  48. #!/bin/bash -ue
  49. # The udev rule is not terribly accurate and may trigger our service before
  50. # the kernel has finished probing partitions. Sleep for a bit to ensure
  51. # the kernel is done.
  52. #
  53. # This can be avoided by using a more precise udev rule, e.g. matching
  54. # a specific hardware path and partition.
  55. sleep 5
  56. #
  57. # Script configuration
  58. #
  59. # The backup partition is mounted there
  60. MOUNTPOINT=/mnt/backup
  61. # This is the location of the Borg repository
  62. TARGET=$MOUNTPOINT/borg-backups/backup.borg
  63. # Archive name schema
  64. DATE=$(date --iso-8601)-$(hostname)
  65. # This is the file that will later contain UUIDs of registered backup drives
  66. DISKS=/etc/backups/backup.disks
  67. # Find whether the connected block device is a backup drive
  68. for uuid in $(lsblk --noheadings --list --output uuid)
  69. do
  70. if grep --quiet --fixed-strings $uuid $DISKS; then
  71. break
  72. fi
  73. uuid=
  74. done
  75. if [ ! $uuid ]; then
  76. echo "No backup disk found, exiting"
  77. exit 0
  78. fi
  79. echo "Disk $uuid is a backup disk"
  80. partition_path=/dev/disk/by-uuid/$uuid
  81. # Mount file system if not already done. This assumes that if something is already
  82. # mounted at $MOUNTPOINT, it is the backup drive. It won't find the drive if
  83. # it was mounted somewhere else.
  84. (mount | grep $MOUNTPOINT) || mount $partition_path $MOUNTPOINT
  85. drive=$(lsblk --inverse --noheadings --list --paths --output name $partition_path | head --lines 1)
  86. echo "Drive path: $drive"
  87. #
  88. # Create backups
  89. #
  90. # Options for borg create
  91. BORG_OPTS="--stats --one-file-system --compression lz4 --checkpoint-interval 86400"
  92. # Set BORG_PASSPHRASE or BORG_PASSCOMMAND somewhere around here, using export,
  93. # if encryption is used.
  94. # No one can answer if Borg asks these questions, it is better to just fail quickly
  95. # instead of hanging.
  96. export BORG_RELOCATED_REPO_ACCESS_IS_OK=no
  97. export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=no
  98. # Log Borg version
  99. borg --version
  100. echo "Starting backup for $DATE"
  101. # This is just an example, change it however you see fit
  102. borg create $BORG_OPTS \
  103. --exclude root/.cache \
  104. --exclude var/lib/docker/devicemapper \
  105. $TARGET::$DATE-$$-system \
  106. / /boot
  107. # /home is often a separate partition / file system.
  108. # Even if it isn't (add --exclude /home above), it probably makes sense
  109. # to have /home in a separate archive.
  110. borg create $BORG_OPTS \
  111. --exclude 'sh:home/*/.cache' \
  112. $TARGET::$DATE-$$-home \
  113. /home/
  114. echo "Completed backup for $DATE"
  115. # Just to be completely paranoid
  116. sync
  117. if [ -f /etc/backups/autoeject ]; then
  118. umount $MOUNTPOINT
  119. hdparm -Y $drive
  120. fi
  121. if [ -f /etc/backups/backup-suspend ]; then
  122. systemctl suspend
  123. fi
  124. Create the ``/etc/backups/autoeject`` file to have the script automatically eject the drive
  125. after creating the backup. Rename the file to something else (e.g. ``/etc/backup/autoeject-no``)
  126. when you want to do something with the drive after creating backups (e.g running check).
  127. Create the ``/etc/backups/backup-suspend`` file if the machine should suspend after completing
  128. the backup. Don't forget to disconnect the device physically before resuming,
  129. otherwise you'll enter a cycle. You can also add an option to power down instead.
  130. Create an empty ``/etc/backups/backup.disks`` file, you'll register your backup drives
  131. there.
  132. The last part is actually to enable the udev rules and services:
  133. .. code-block:: bash
  134. ln -s /etc/backups/40-backup.rules /etc/udev/rules.d/40-backup.rules
  135. ln -s /etc/backups/automatic-backup.service /etc/systemd/system/automatic-backup.service
  136. systemctl daemon-reload
  137. udevadm control --reload
  138. Adding backup hard drives
  139. -------------------------
  140. Connect your backup hard drive. Format it, if not done already.
  141. Find the UUID of the file system that backups should be stored on::
  142. lsblk -o+uuid,label
  143. Note the UUID into the ``/etc/backup/backup.disks`` file.
  144. Mount the drive to /mnt/backup.
  145. Initialize a Borg repository at the location indicated by ``TARGET``::
  146. borg init --encryption ... /mnt/backup/borg-backups/backup.borg
  147. Unmount and reconnect the drive, or manually start the ``automatic-backup`` service
  148. to start the first backup::
  149. systemctl start --no-block automatic-backup
  150. See backup logs using journalctl::
  151. journalctl -fu automatic-backup [-n number-of-lines]
  152. Security considerations
  153. -----------------------
  154. The script as shown above will mount any file system with an UUID listed in
  155. ``/etc/backup/backup.disks``. The UUID check is a safety / annoyance-reduction
  156. mechanism to keep the script from blowing up whenever a random USB thumb drive is connected.
  157. It is not meant as a security mechanism. Mounting file systems and reading repository
  158. data exposes additional attack surfaces (kernel file system drivers,
  159. possibly user space services and Borg itself). On the other hand, someone
  160. standing right next to your computer can attempt a lot of attacks, most of which
  161. are easier to do than e.g. exploiting file systems (installing a physical key logger,
  162. DMA attacks, stealing the machine, ...).
  163. Borg ensures that backups are not created on random drives that "just happen"
  164. to contain a Borg repository. If an unknown unencrypted repository is encountered,
  165. then the script aborts (BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=no).
  166. Backups are only created on hard drives that contain a Borg repository that is
  167. either known (by ID) to your machine or you are using encryption and the
  168. passphrase of the repository has to match the passphrase supplied to Borg.