diff --git a/immich_backup.md b/immich_backup.md deleted file mode 100644 index 75793d0..0000000 --- a/immich_backup.md +++ /dev/null @@ -1,489 +0,0 @@ ---- -title: Immich Backup and Restore -description: Immich backup with Kopia -published: true -date: 2026-02-14T03:16:12.150Z -tags: -editor: markdown -dateCreated: 2026-02-14T03:14:32.594Z ---- - -# Immich Backup and Recovery Guide - -## Overview - -This document provides comprehensive backup and recovery procedures for Immich photo management server. Following the same proven strategy as our Mailcow backups, we use a **two-tier approach** combining local component-level backups with Kopia for offsite storage in vaults. - -## Quick Reference - -### Common Backup Commands - -```bash -# Run a manual backup (all components) -/opt/scripts/backup-immich.sh - -# List Kopia snapshots -kopia snapshot list --tags immich - -# View backup logs -tail -f /var/log/immich-backup.log -``` - -### Common Restore Commands - -```bash -# Restore from local backup (interactive) -/opt/immich-backups/immich-restore.sh /opt/immich-backups/immich-YYYYMMDD_HHMMSS/ - -# Restore from Kopia to new server -kopia snapshot list --tags tier1-backup -kopia restore /opt/immich-backups/ - -# Check container status after restore -docker compose ps -docker compose logs -f -``` - -## Critical Components to Backup - -### 1. Docker Compose Configuration -- **Location**: `/opt/immich/docker-compose.yml` -- **Purpose**: Defines all containers, networks, and volumes -- **Importance**: Critical for recreating the exact container configuration - -### 2. Environment Configuration -- **Primary Config**: `/opt/immich/.env` -- **Purpose**: Database credentials, upload locations, API keys -- **Importance**: Required for proper service initialization - -### 3. PostgreSQL Database -- **Purpose**: Contains all metadata, user accounts, albums, sharing settings, face recognition data -- **Docker Volume**: `immich_postgres` -- **Backup Method**: `pg_dumpall` (hot backup, no downtime) - -### 4. Photo/Video Library -- **Purpose**: All original photos and videos uploaded by users -- **Docker Volume**: `immich_upload` or `immich_library` -- **Size**: Typically the largest component -- **Critical**: This is your actual data - photos cannot be recreated - -### 5. Additional Important Data -- **Thumbnails**: Can be regenerated but saves processing time -- **Encoded Video**: Transcoded versions, can be regenerated -- **Profile Pictures**: User avatars -- **Machine Learning Models**: Can be re-downloaded - -## Backup Strategy - -### Two-Tier Backup Approach - -We use a **two-tier approach** combining local snapshots with Kopia for offsite storage: - -1. **Tier 1 (Local)**: Component-level backups (database dump + volume archives) -2. **Tier 2 (Offsite)**: Kopia snapshots the local backups and syncs to vaults - -#### Why This Approach? - -- **Best of both worlds**: Local backups ensure quick component-level restore, Kopia provides deduplication and offsite protection -- **Component-level restore**: Can restore individual components (just database, just photos, etc.) -- **Disaster recovery**: Full system restore from Kopia backups on new server -- **Efficient storage**: Kopia's deduplication reduces storage needs for offsite copies -- **Proven strategy**: Same approach used successfully for Mailcow backups - -#### Backup Frequency -- **Daily**: Local Tier 1 backup runs at 2 AM -- **Daily**: Kopia Tier 2 snapshot runs immediately after Tier 1 -- **Retention (Local)**: 7 days of local backups -- **Retention (Kopia/Offsite)**: 30 daily, 12 weekly, 12 monthly - -### What Gets Backed Up - -Each backup creates: -- **database.sql.gz**: Complete PostgreSQL dump -- **immich_*.tar.gz**: Compressed archives of each Docker volume -- **docker-compose.yml**: Container configuration -- **.env**: Environment variables and secrets -- **manifest.txt**: Backup inventory and sizes -- **checksums.sha256**: Integrity verification - -## Setting Up Immich Backups - -### Prerequisites - -Connect to Kopia Repository: - -```bash -sudo kopia repository connect server \ - --url=https://192.168.5.10:51516 \ - --override-username=admin \ - --server-cert-fingerprint=YOUR_FINGERPRINT_HERE -``` - -### Step 1: Configure Backup Location - -```bash -sudo mkdir -p /opt/immich-backups -sudo chown -R root:root /opt/immich-backups -sudo chmod 755 /opt/immich-backups -``` - -### Step 2: Install Backup Scripts - -```bash -sudo mkdir -p /opt/scripts - -sudo cp immich-backup.sh /opt/scripts/backup-immich.sh -sudo cp immich-restore.sh /opt/immich-backups/immich-restore.sh - -sudo chmod +x /opt/scripts/backup-immich.sh -sudo chmod +x /opt/immich-backups/immich-restore.sh -``` - -### Step 3: Configure Backup Script - -Edit `/opt/scripts/backup-immich.sh` and verify: - -```bash -BACKUP_DIR="/opt/immich-backups" -RETENTION_DAYS=7 -IMMICH_DIR="/opt/immich" -POSTGRES_CONTAINER="immich_postgres" -PROJECT_NAME="immich" -ENABLE_KOPIA=true -``` - -Find your PostgreSQL container: -```bash -docker ps | grep postgres -``` - -### Step 4: Test Manual Backup - -```bash -sudo /opt/scripts/backup-immich.sh -``` - -Verify: -```bash -ls -lh /opt/immich-backups/ -kopia snapshot list --tags immich -``` - -### Step 5: Automated Backup with Cron - -```bash -sudo crontab -e -``` - -Add for daily backups at 2 AM: -``` -0 2 * * * /opt/scripts/backup-immich.sh 2>&1 | logger -t immich-backup -``` - -### Step 6: Configure Kopia Retention - -```bash -kopia policy set /opt/immich-backups \ - --keep-latest 30 \ - --keep-daily 30 \ - --keep-weekly 12 \ - --keep-monthly 12 - -kopia policy set /opt/immich \ - --keep-latest 7 \ - --keep-daily 7 -``` - -## Recovery Procedures - -### Method 1: Local Restore (Recommended) - -Full system restore: - -```bash -ls -lh /opt/immich-backups/ - -sudo /opt/immich-backups/immich-restore.sh /opt/immich-backups/immich-YYYYMMDD_HHMMSS/ -``` - -Database-only restore: - -```bash -cd /opt/immich -docker compose down -docker compose up -d postgres -sleep 10 - -BACKUP_PATH="/opt/immich-backups/immich-YYYYMMDD_HHMMSS" -gunzip < "${BACKUP_PATH}/database.sql.gz" | docker exec -i immich_postgres psql -U postgres - -docker compose down -docker compose up -d -``` - -Volume-only restore: - -```bash -cd /opt/immich -docker compose down - -BACKUP_PATH="/opt/immich-backups/immich-YYYYMMDD_HHMMSS" -VOLUME_NAME="immich_upload" - -docker run --rm \ - -v "${VOLUME_NAME}:/data" \ - -v "${BACKUP_PATH}:/backup" \ - alpine sh -c "cd /data && tar -xzf /backup/${VOLUME_NAME}.tar.gz" - -docker compose up -d -``` - -### Method 2: Complete Server Rebuild - -#### Step 1: Prepare New Server - -```bash -# Install Docker -curl -fsSL https://get.docker.com | sh -sudo systemctl enable docker -sudo apt install docker-compose-plugin -y - -# Install Kopia -curl -s https://kopia.io/signing-key | sudo gpg --dearmor -o /usr/share/keyrings/kopia-keyring.gpg -echo "deb [signed-by=/usr/share/keyrings/kopia-keyring.gpg] https://packages.kopia.io/apt/ stable main" | sudo tee /etc/apt/sources.list.d/kopia.list -sudo apt update && sudo apt install kopia -y - -# Create directories -sudo mkdir -p /opt/immich /opt/immich-backups /opt/scripts -``` - -#### Step 2: Connect to Kopia - -```bash -sudo kopia repository connect server \ - --url=https://YOUR_KOPIA_SERVER:51516 \ - --override-username=admin \ - --server-cert-fingerprint=YOUR_FINGERPRINT - -kopia repository status -``` - -#### Step 3: Restore Configuration - -```bash -kopia snapshot list --tags config -kopia restore /opt/immich/ - -ls -la /opt/immich/docker-compose.yml -ls -la /opt/immich/.env -``` - -#### Step 4: Restore Backups - -```bash -kopia snapshot list --tags tier1-backup -kopia restore /opt/immich-backups/ - -ls -la /opt/immich-backups/ -``` - -#### Step 5: Run Local Restore - -```bash -LATEST_BACKUP=$(ls -td /opt/immich-backups/immich-* | head -1) -sudo /opt/immich-backups/immich-restore.sh "$LATEST_BACKUP" -``` - -#### Step 6: Start and Verify - -```bash -cd /opt/immich -docker compose pull -docker compose up -d -docker compose logs -f -``` - -Verify: -- [ ] All containers running: `docker compose ps` -- [ ] Web interface accessible: `curl -I http://localhost:2283` -- [ ] Database accessible: `docker compose exec postgres psql -U postgres -c "\l"` -- [ ] Photos visible: `docker compose exec immich_server ls /usr/src/app/upload/` -- [ ] Login and check albums, timeline, sharing - -## Verification and Testing - -Monthly backup verification: - -```bash -# Verify local backups -ls -lth /opt/immich-backups/ | head -5 - -# Verify checksums -LATEST_BACKUP=$(ls -td /opt/immich-backups/immich-* | head -1) -cd "$LATEST_BACKUP" && sha256sum -c checksums.sha256 - -# Verify Kopia snapshots -kopia snapshot list --tags immich -``` - -### Backup Monitoring Script - -Create `/opt/scripts/check-immich-backup.sh`: - -```bash -#!/bin/bash - -LAST_BACKUP=$(ls -td /opt/immich-backups/immich-* | head -1) - -if [ -z "$LAST_BACKUP" ]; then - echo "ERROR: No backups found!" - exit 1 -fi - -BACKUP_DATE=$(basename "$LAST_BACKUP" | sed 's/immich-//') -BACKUP_EPOCH=$(date -d "${BACKUP_DATE:0:8} ${BACKUP_DATE:9:2}:${BACKUP_DATE:11:2}:${BACKUP_DATE:13:2}" +%s 2>/dev/null) -NOW=$(date +%s) -AGE_HOURS=$(( ($NOW - $BACKUP_EPOCH) / 3600 )) - -if [ $AGE_HOURS -gt 26 ]; then - echo "WARNING: Last Immich backup is $AGE_HOURS hours old" - exit 1 -else - echo "OK: Last backup $AGE_HOURS hours ago" - BACKUP_SIZE=$(du -sh "$LAST_BACKUP" | cut -f1) - echo "Size: $BACKUP_SIZE" -fi -``` - -Add to cron: -```bash -chmod +x /opt/scripts/check-immich-backup.sh -sudo crontab -e -0 8 * * * /opt/scripts/check-immich-backup.sh | logger -t immich-backup-check -``` - -## Disaster Recovery Checklist - -- [ ] Confirm scope of failure -- [ ] Access offsite Kopia repository -- [ ] Provision new server with Docker and Kopia -- [ ] Connect to Kopia repository -- [ ] Restore configuration from Kopia -- [ ] Restore backup directory from Kopia -- [ ] Run local restore script -- [ ] Start Immich containers -- [ ] Verify web interface and photo access -- [ ] Update DNS if needed -- [ ] Document issues and lessons learned - -## Important Notes - -1. **Machine Learning Models**: Can be excluded from backup (re-download automatically) -2. **Photo Deduplication**: Remains intact after restore -3. **Facial Recognition**: Stored in database, restored automatically -4. **Permissions**: Handled automatically by Docker -5. **Upgrades**: Always restore with same or newer Immich version -6. **DNS**: Update if restoring to new server IP - -## Troubleshooting - -### "Database backup failed" -```bash -docker ps | grep postgres -docker compose logs postgres -docker exec immich_postgres pg_dumpall -U postgres | head -``` - -### "Volume not found" -```bash -docker volume ls | grep immich -docker compose up -d --no-start -docker volume ls -``` - -### "Kopia snapshot fails" -```bash -kopia repository status -kopia repository connect server --url=... -kopia snapshot create /opt/immich-backups -``` - -### "Photos missing after restore" -```bash -docker compose exec immich_server ls -lah /usr/src/app/upload/ -docker volume inspect immich_upload -docker compose logs -f immich_server -``` - -## Advanced Topics - -### Exclude Components to Save Space - -Edit backup script to exclude thumbnails/encoded videos: - -```bash -docker volume ls --filter "name=${PROJECT_NAME}" --format "{{.Name}}" | grep -v "thumbs" -``` - -### Incremental Backups - -``` -# Daily: Database + config only -0 2 * * 1-6 /opt/scripts/backup-immich-db-only.sh - -# Weekly: Full backup -0 2 * * 0 /opt/scripts/backup-immich.sh -``` - -### Backup Notifications - -Add to end of backup script: - -```bash -ADMIN_EMAIL="admin@example.com" -echo "Immich backup completed: ${TIER1_SIZE}" | \ - mail -s "✓ Immich Backup Success" "$ADMIN_EMAIL" - -curl -fsS --retry 3 https://hc-ping.com/your-uuid-here -``` - -## Backup Architecture Notes - -### Storage Efficiency Example - -For a 500GB photo library: - -**Without Kopia**: -- 7 days × 500GB = 3.5TB local storage - -**With Two-Tier**: -- Local: 3.5TB (7 days) -- Kopia vault: ~500GB + (30 × 10GB) = ~800GB -- **Savings**: 70-80% in vault storage - -### Component Restore Priority - -| Component | When to Restore | Can Regenerate? | Priority | -|-----------|----------------|-----------------|----------| -| Database | Always | No | Critical | -| Upload/Library | Always | No | Critical | -| Thumbnails | Optional | Yes | Medium | -| Encoded Videos | Optional | Yes | Low | -| Model Cache | Never | Yes | Low | - -## Additional Resources - -- [Immich Official Documentation](https://immich.app/docs) -- [Kopia Documentation](https://kopia.io/docs/) -- [Docker Volume Backup Best Practices](https://docs.docker.com/storage/volumes/#back-up-restore-or-migrate-data-volumes) - -## Revision History - -| Date | Version | Changes | -|------|---------|---------| -| 2026-02-13 | 1.0 | Initial documentation - two-tier backup strategy | - ---- - -**Last Updated**: February 13, 2026 -**Review Schedule**: Quarterly