aboutsummaryrefslogtreecommitdiff
path: root/tw/services/files/nextcloud-backup
diff options
context:
space:
mode:
Diffstat (limited to 'tw/services/files/nextcloud-backup')
-rwxr-xr-xtw/services/files/nextcloud-backup68
1 files changed, 68 insertions, 0 deletions
diff --git a/tw/services/files/nextcloud-backup b/tw/services/files/nextcloud-backup
new file mode 100755
index 00000000..4c533758
--- /dev/null
+++ b/tw/services/files/nextcloud-backup
@@ -0,0 +1,68 @@
+#!/bin/sh -e
+# Nextcloud backup script, to run nightly.
+# Documentation on backups:
+# https://docs.nextcloud.com/server/latest/admin_manual/maintenance/backup.html
+# https://docs.nextcloud.com/server/latest/admin_manual/maintenance/restore.html
+# https://git.mdns.eu/nextcloud/passwords/-/wikis/Administrators/Backups
+
+. /etc/default/nextcloud-backup
+: "${DATABASE_PASSWORD:?You must pass the MySQL database password as DATABASE_PASSWORD}"
+
+php_ini=$1
+backup_dir=/var/backups/nextcloud/$(date -u '+%Y-%m-%d')
+nextcloud_dir=/var/www/nextcloud
+nextcloud_data_partition=/var/data # mountpoint of the partition containing Nextcloud data dir
+nextcloud_data_path=nextcloud # relative to $nextcloud_data_partition
+snapshot=$nextcloud_data_partition/tmp-nextcloud-backup
+
+nc_maintenance () {
+ # Enable (--on) or disable (--off) Nextcloud's maintenance mode.
+ sudo -nu httpd php ${php_ini:+-c "$php_ini"} "$nextcloud_dir/occ" maintenance:mode "$@"
+}
+
+# If there is a previous backup, compare against it later (so we don't have to
+# transfer every file).
+last_backup_dir=$(ls -1d "$(dirname "$backup_dir")"/????-??-?? | LC_ALL=C sort | tail -1)
+[ -d "$last_backup_dir" ] || unset last_backup_dir
+
+# Don't overwrite existing backups. mkdir will fail if $backup_dir exists.
+mkdir -m 750 "$backup_dir"
+
+# Always turn off maintenance mode and clean up the temporary snapshot on exit,
+# whether or not the backup succeeded.
+cleanup () {
+ nc_maintenance --off || :
+ if [ -d "$snapshot" ]; then
+ btrfs subvolume delete -c "$snapshot" || :
+ fi
+}
+trap cleanup EXIT HUP INT TERM # can't trap KILL
+
+# Turn Nextcloud off temporarily so the data doesn't change during the backup.
+nc_maintenance --on
+
+# Backup the database. This can only be done offline.
+mysqldump --single-transaction --default-character-set=utf8mb4 \
+ -u nextcloud -p"$DATABASE_PASSWORD" nextcloud > "$backup_dir/nextcloud.sql"
+
+# These shouldn't be copied while Nextcloud is online.
+rsync -AUXHavx ${last_backup_dir+--link-dest="$last_backup_dir"} \
+ "$nextcloud_dir/config" "$nextcloud_dir/themes" "$backup_dir"
+
+# Make sure everything is synced to disk so it's in our snapshot.
+btrfs filesystem sync "$nextcloud_data_partition/$nextcloud_data_path"
+btrfs subvolume snapshot -r "$nextcloud_data_partition" "$snapshot"
+
+# At this point, the data directory is in the snapshot, so Nextcloud can be
+# turned on again.
+nc_maintenance --off
+
+# --link-dest is brittle (it only hardlinks to the old file if no metadata has
+# changed). Reflinks would be better, but rsync doesn't seem to support them.
+# We don't need files under preview/, as those are thumbnails from the Previews
+# "app" and can be regenerated using `php -f occ preview:pre-generate`.
+rsync -AUXHavx --exclude='appdata_*/preview' --exclude='appdata_*/passwords/*Cache' \
+ ${last_backup_dir+--link-dest="$last_backup_dir/data"} \
+ "$snapshot/$nextcloud_data_path/" "$backup_dir/data"
+# Make sure everything is written out to the backup disk before we exit.
+btrfs filesystem sync "$backup_dir"