#!/bin/bash # Daily USB backup. Dumps DBs for consistency, then rsyncs everything. set -euo pipefail FAILURES=() # Check the USB drive is actually mounted if ! mountpoint -q /mnt/backup; then echo "FATAL: /mnt/backup is not mounted" >&2 exit 1 fi # Dump Nextcloud PostgreSQL for consistency if docker exec nextcloud-db pg_dumpall -U nextcloud > /opt/argento/docker/nextcloud/db/pg_dumpall.sql.tmp; then mv /opt/argento/docker/nextcloud/db/pg_dumpall.sql.tmp /opt/argento/docker/nextcloud/db/pg_dumpall.sql else rm -f /opt/argento/docker/nextcloud/db/pg_dumpall.sql.tmp FAILURES+=("nextcloud pg_dump") fi # Dump Gitea SQLite for consistency sqlite3 /opt/argento/docker/gitea/data/gitea/gitea.db \ ".backup /opt/argento/docker/gitea/data/gitea/gitea.db.bak" \ || FAILURES+=("gitea sqlite backup") # Dump Jellyfin SQLite DBs for consistency for db in jellyfin library; do sqlite3 /opt/argento/docker/jellyfin/config/data/${db}.db \ ".backup /opt/argento/docker/jellyfin/config/data/${db}.db.bak" \ || FAILURES+=("jellyfin ${db} sqlite backup") done # Single rsync covers everything: configs, app data, media, DB dumps RSYNC_OPTS="-a --delete" [ -t 1 ] && RSYNC_OPTS="$RSYNC_OPTS --info=progress2" rsync $RSYNC_OPTS /opt/argento/ /mnt/backup/argento/ \ || FAILURES+=("rsync argento") if [ ${#FAILURES[@]} -gt 0 ]; then echo "BACKUP FAILED: ${FAILURES[*]}" >&2 exit 1 fi echo "Backup completed successfully at $(date)"