|
@@ -0,0 +1,194 @@
|
|
1
|
+title: Blog
|
|
2
|
+post: BorgBackup automation scripts
|
|
3
|
+description: Distributed, encrypted, deduplicated and compressed backups
|
|
4
|
+date: 2022-05-16
|
|
5
|
+comments: true
|
|
6
|
+---
|
|
7
|
+
|
|
8
|
+I have been using [BorgBackup](https://www.borgbackup.org/) for a while now to backup my machines to external drives and a NAS.
|
|
9
|
+For more convenience I created a set of scripts to automate this process.
|
|
10
|
+
|
|
11
|
+The first part is a script doing the actual backup process by calling borg.
|
|
12
|
+This is inspired by [the example script in the documentation](https://borgbackup.readthedocs.io/en/stable/quickstart.html#automating-backups).
|
|
13
|
+
|
|
14
|
+<pre class="sh_sh">
|
|
15
|
+#!/bin/sh
|
|
16
|
+
|
|
17
|
+# ~/bin/backup-borg
|
|
18
|
+
|
|
19
|
+# Helper script for automated borg backups.
|
|
20
|
+# BACKUP_PATH, BACKUP_EXCLUDES, BORG_REPO and BORG_PASSPHRASE
|
|
21
|
+# should already be set in environment from calling script!
|
|
22
|
+
|
|
23
|
+if [[ -z "$BACKUP_PATH" ]]; then
|
|
24
|
+ echo "Please set BACKUP_PATH before calling"
|
|
25
|
+ exit 1
|
|
26
|
+fi
|
|
27
|
+if [[ -z "$BACKUP_EXCLUDES" ]]; then
|
|
28
|
+ echo "Please set BACKUP_EXCLUDES before calling"
|
|
29
|
+ exit 1
|
|
30
|
+fi
|
|
31
|
+if [[ -z "$BORG_REPO" ]]; then
|
|
32
|
+ echo "Please set BORG_REPO before calling"
|
|
33
|
+ exit 1
|
|
34
|
+fi
|
|
35
|
+# $BORG_PASSPHRASE is allowed to be empty
|
|
36
|
+
|
|
37
|
+# some helpers and error handling:
|
|
38
|
+info() { printf "\n%s\n%s\n\n" "$( date )" "$*" >&2; }
|
|
39
|
+trap 'echo $( date ) Backup interrupted >&2; exit 2' INT TERM
|
|
40
|
+
|
|
41
|
+info "Starting backup"
|
|
42
|
+
|
|
43
|
+# Backup the most important directories into an archive named after
|
|
44
|
+# the machine this script is currently running on:
|
|
45
|
+
|
|
46
|
+borg create \
|
|
47
|
+ --verbose \
|
|
48
|
+ --list \
|
|
49
|
+ --filter E \
|
|
50
|
+ --stats \
|
|
51
|
+ --progress \
|
|
52
|
+ --show-version \
|
|
53
|
+ --show-rc \
|
|
54
|
+ --compression lz4 \
|
|
55
|
+ --exclude-caches \
|
|
56
|
+ $BACKUP_EXCLUDES \
|
|
57
|
+ \
|
|
58
|
+ ::'{hostname}-{now}' \
|
|
59
|
+ $BACKUP_PATH
|
|
60
|
+
|
|
61
|
+backup_exit=$?
|
|
62
|
+
|
|
63
|
+info "Pruning repository"
|
|
64
|
+
|
|
65
|
+# Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
|
|
66
|
+# archives of THIS machine. The '{hostname}-' prefix is very important to
|
|
67
|
+# limit prune's operation to this machine's archives and not apply to
|
|
68
|
+# other machines' archives also:
|
|
69
|
+
|
|
70
|
+borg prune \
|
|
71
|
+ --verbose \
|
|
72
|
+ --list \
|
|
73
|
+ --prefix '{hostname}-' \
|
|
74
|
+ --progress \
|
|
75
|
+ --show-version \
|
|
76
|
+ --show-rc \
|
|
77
|
+ --keep-daily 7 \
|
|
78
|
+ --keep-weekly 4 \
|
|
79
|
+ --keep-monthly 6
|
|
80
|
+
|
|
81
|
+prune_exit=$?
|
|
82
|
+
|
|
83
|
+info "Compacting repository"
|
|
84
|
+
|
|
85
|
+# Also do a compact after each prune, to free space
|
|
86
|
+borg compact \
|
|
87
|
+ --verbose \
|
|
88
|
+ --progress \
|
|
89
|
+ --show-version \
|
|
90
|
+ --show-rc
|
|
91
|
+
|
|
92
|
+compact_exit=$?
|
|
93
|
+
|
|
94
|
+# use highest exit code as global exit code
|
|
95
|
+bp_exit=$(( backup_exit > prune_exit ? backup_exit : prune_exit ))
|
|
96
|
+global_exit=$(( bp_exit > compact_exit ? bp_exit : compact_exit ))
|
|
97
|
+
|
|
98
|
+if [ ${global_exit} -eq 1 ];
|
|
99
|
+then
|
|
100
|
+ info "Backup finished with a warning"
|
|
101
|
+fi
|
|
102
|
+
|
|
103
|
+if [ ${global_exit} -gt 1 ];
|
|
104
|
+then
|
|
105
|
+ info "Backup finished with an error"
|
|
106
|
+fi
|
|
107
|
+
|
|
108
|
+exit ${global_exit}
|
|
109
|
+</pre>
|
|
110
|
+
|
|
111
|
+Run the following commands to create a new repository and export it's key.
|
|
112
|
+This key needs to be stored somewhere safe, along with the password you set in the first command.
|
|
113
|
+
|
|
114
|
+ borg init --encryption=repokey /path/to/repo
|
|
115
|
+ borg key export /path/to/repo key-file-name
|
|
116
|
+
|
|
117
|
+I have multiple different borg repositories on various disks and machines.
|
|
118
|
+For each combination of backup input and output location, I created another script, calling the previous one with the proper values for location, excludes and repository password.
|
|
119
|
+
|
|
120
|
+<pre class="sh_sh">
|
|
121
|
+#!/bin/sh
|
|
122
|
+
|
|
123
|
+# ~/bin/backup-root-extern
|
|
124
|
+
|
|
125
|
+export BORG_REPO=/mnt/backup/borg-linux-root
|
|
126
|
+export BORG_PASSPHRASE='REDACTED'
|
|
127
|
+
|
|
128
|
+export BACKUP_PATH=/
|
|
129
|
+export BACKUP_EXCLUDES=" \
|
|
130
|
+ --exclude=/home/* \
|
|
131
|
+ --exclude=/var/cache/* \
|
|
132
|
+ --exclude=/var/tmp/* \
|
|
133
|
+ --exclude=/media/* \
|
|
134
|
+ --exclude=/mnt/* \
|
|
135
|
+ --exclude=/dev/* \
|
|
136
|
+ --exclude=/proc/* \
|
|
137
|
+ --exclude=/sys/* \
|
|
138
|
+ --exclude=/tmp/* \
|
|
139
|
+ --exclude=/run/* \
|
|
140
|
+ --exclude=/lost+found/* \
|
|
141
|
+"
|
|
142
|
+
|
|
143
|
+backup-borg
|
|
144
|
+
|
|
145
|
+backup_exit=$?
|
|
146
|
+exit ${backup_exit}
|
|
147
|
+</pre>
|
|
148
|
+
|
|
149
|
+For convenience, I created yet another script that does all the backups into the same locations / machine.
|
|
150
|
+
|
|
151
|
+<pre class="sh_sh">
|
|
152
|
+#!/bin/sh
|
|
153
|
+
|
|
154
|
+# ~/bin/backup-extern
|
|
155
|
+
|
|
156
|
+sudo backup-root-extern
|
|
157
|
+root_exit=$?
|
|
158
|
+
|
|
159
|
+sudo backup-home-extern
|
|
160
|
+home_exit=$?
|
|
161
|
+
|
|
162
|
+sudo backup-data-extern
|
|
163
|
+data_exit=$?
|
|
164
|
+
|
|
165
|
+# use highest exit code as global exit code
|
|
166
|
+rh_exit=$(( root_exit > home_exit ? root_exit : home_exit ))
|
|
167
|
+global_exit=$(( rh_exit > data_exit ? rh_exit : data_exit ))
|
|
168
|
+
|
|
169
|
+if [ ${global_exit} -eq 1 ];
|
|
170
|
+then
|
|
171
|
+ echo "One or Multiple Backups finished with a warning"
|
|
172
|
+fi
|
|
173
|
+
|
|
174
|
+if [ ${global_exit} -gt 1 ];
|
|
175
|
+then
|
|
176
|
+ echo "One or Multiple Backups finished with an error"
|
|
177
|
+fi
|
|
178
|
+
|
|
179
|
+exit ${global_exit}
|
|
180
|
+</pre>
|
|
181
|
+
|
|
182
|
+Which can easily be combined with the following script, which tries to mount one of the external backup disks I rotate through.
|
|
183
|
+
|
|
184
|
+<pre class="sh_sh">
|
|
185
|
+#!/bin/bash
|
|
186
|
+
|
|
187
|
+# ~/bin/mount-backup
|
|
188
|
+
|
|
189
|
+( sudo mount -U xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt/backup -t ext4 ||
|
|
190
|
+ sudo mount -U xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt/backup -t ext4
|
|
191
|
+) && echo ok
|
|
192
|
+</pre>
|
|
193
|
+
|
|
194
|
+I can now simply plug in a backup disk and run "mount-backup && backup-extern" to run a new backup.
|