#!/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"