#!/bin/bash # # Purpose : Back up your home folder with borg to your Nextcloud files, in # /mnt//.backup-. Run daily by # coredesktop-backup.timer; `configure backup` sets it up. # # Keeps 7 daily, 4 weekly and 6 monthly backups. To leave out more, list # paths or borg patterns in ~/.config/coredesktop/backup-exclude, one per line. # Wrapped in { ...; exit; } so bash reads the whole script up front; update # replaces this file (git pull) while a backup may be running. { BACKUP_CONF="$HOME/.config/coredesktop/backup.conf" USER_EXCLUDE="$HOME/.config/coredesktop/backup-exclude" # Tell the desktop when a backup fails, as no one watches the timer fail() { echo "$1" >&2 notify-send --app-name=CoreDesktop --icon=dialog-error "Backup failed" "$1" 2> /dev/null exit 1 } [ -f "$BACKUP_CONF" ] || fail "Backups aren't set up. Run: configure backup" source "$BACKUP_CONF" # The files mount comes up at login, perhaps before the network; give it a # few minutes rather than writing into the empty folder underneath for try in {1..10}; do mountpoint -q "$BACKUP_MOUNT" && break mount "$BACKUP_MOUNT" 2> /dev/null && break sleep 30 done mountpoint -q "$BACKUP_MOUNT" || fail "Your Nextcloud files aren't mounted at $BACKUP_MOUNT." export BORG_REPO export BORG_PASSCOMMAND="secret-tool lookup coredesktop backup repo $BORG_REPO" # Rebuilt by borg, or by reinstalling, so not worth the space excludes=( "$HOME/.cache" "$HOME/.davfs2/cache" "$HOME/.local/share/Trash" "$HOME/.local/share/containers" "$HOME/.local/share/flatpak" "$HOME/.local/share/siblings" "$HOME/.local/share/coredesktop" "$HOME/.var/app/*/cache" "$HOME/.npm" "$HOME/.cargo/registry" "$HOME/go/pkg/mod" ) exclude_args=(--exclude-caches) for path in "${excludes[@]}"; do exclude_args+=(--exclude "sh:$path") done [ -f "$USER_EXCLUDE" ] && exclude_args+=(--exclude-from "$USER_EXCLUDE") echo "Backing up $HOME to $BORG_REPO..." # --one-file-system leaves out other mounts and btrfs subvolumes inside home borg create --one-file-system --compression zstd --stats \ "${exclude_args[@]}" "::{hostname}-{now:%Y-%m-%dT%H:%M}" "$HOME" status=$? # 1 is a warning, e.g. a file changed while it was read; the backup still exists (( status <= 1 )) || fail "borg couldn't back up $HOME (exit $status). See: journalctl --user -u coredesktop-backup" echo "Removing old backups..." borg prune --glob-archives '{hostname}-*' \ --keep-daily 7 --keep-weekly 4 --keep-monthly 6 \ || fail "borg couldn't remove old backups. See: journalctl --user -u coredesktop-backup" borg compact || fail "borg couldn't free space from old backups. See: journalctl --user -u coredesktop-backup" echo "Backup finished." exit 0 }