From e2e15009e28f27a919aef368836c817af440235b Mon Sep 17 00:00:00 2001 From: Alvis Date: Sat, 7 Mar 2026 18:28:58 +0000 Subject: [PATCH] Add Immich backup script Daily backup at 02:30 via root cron: DB dump + rsync of library/upload/profile to /mnt/backups/media/. Retains 14 days of DB dumps. Monitored via Zabbix immich.backup.age item with High trigger if stale >25h. Co-Authored-By: Claude Sonnet 4.6 --- immich-app/backup.sh | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100755 immich-app/backup.sh diff --git a/immich-app/backup.sh b/immich-app/backup.sh new file mode 100755 index 0000000..0de2a41 --- /dev/null +++ b/immich-app/backup.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail + +BACKUP_DIR=/mnt/backups/media +DB_BACKUP_DIR="$BACKUP_DIR/backups" +LOG="$BACKUP_DIR/backup.log" +RETAIN_DAYS=14 + +mkdir -p "$DB_BACKUP_DIR" + +echo "[$(date)] Starting Immich backup" >> "$LOG" + +# 1. Database dump (must come before file sync) +DUMP_FILE="$DB_BACKUP_DIR/immich-db-$(date +%Y%m%dT%H%M%S).sql.gz" +docker exec immich_postgres pg_dump --clean --if-exists \ + --dbname=immich --username=postgres | gzip > "$DUMP_FILE" +echo "[$(date)] DB dump: $DUMP_FILE" >> "$LOG" + +# 2. Rsync critical asset folders (skip thumbs and encoded-video — regeneratable) +for DIR in library upload profile; do + rsync -a --delete /mnt/media/upload/$DIR/ "$BACKUP_DIR/$DIR/" >> "$LOG" 2>&1 + echo "[$(date)] Synced $DIR" >> "$LOG" +done + +# 3. Remove old DB dumps +find "$DB_BACKUP_DIR" -name "immich-db-*.sql.gz" -mtime +$RETAIN_DAYS -delete +echo "[$(date)] Cleaned dumps older than ${RETAIN_DAYS}d" >> "$LOG" + +touch "$BACKUP_DIR/.last_sync" +echo "[$(date)] Immich backup complete" >> "$LOG"