12 KiB
| title | description | published | date | tags | editor | dateCreated |
|---|---|---|---|---|---|---|
| Immich Backup and Restore | Immich backup with Kopia | true | 2026-02-14T03:16:12.150Z | markdown | 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
# 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
# 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 <snapshot-id> /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_uploadorimmich_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:
- Tier 1 (Local): Component-level backups (database dump + volume archives)
- 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:
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
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
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:
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:
docker ps | grep postgres
Step 4: Test Manual Backup
sudo /opt/scripts/backup-immich.sh
Verify:
ls -lh /opt/immich-backups/
kopia snapshot list --tags immich
Step 5: Automated Backup with Cron
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
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:
ls -lh /opt/immich-backups/
sudo /opt/immich-backups/immich-restore.sh /opt/immich-backups/immich-YYYYMMDD_HHMMSS/
Database-only restore:
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:
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
# 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
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
kopia snapshot list --tags config
kopia restore <config-snapshot-id> /opt/immich/
ls -la /opt/immich/docker-compose.yml
ls -la /opt/immich/.env
Step 4: Restore Backups
kopia snapshot list --tags tier1-backup
kopia restore <snapshot-id> /opt/immich-backups/
ls -la /opt/immich-backups/
Step 5: Run Local Restore
LATEST_BACKUP=$(ls -td /opt/immich-backups/immich-* | head -1)
sudo /opt/immich-backups/immich-restore.sh "$LATEST_BACKUP"
Step 6: Start and Verify
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:
# 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:
#!/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:
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
- Machine Learning Models: Can be excluded from backup (re-download automatically)
- Photo Deduplication: Remains intact after restore
- Facial Recognition: Stored in database, restored automatically
- Permissions: Handled automatically by Docker
- Upgrades: Always restore with same or newer Immich version
- DNS: Update if restoring to new server IP
Troubleshooting
"Database backup failed"
docker ps | grep postgres
docker compose logs postgres
docker exec immich_postgres pg_dumpall -U postgres | head
"Volume not found"
docker volume ls | grep immich
docker compose up -d --no-start
docker volume ls
"Kopia snapshot fails"
kopia repository status
kopia repository connect server --url=...
kopia snapshot create /opt/immich-backups
"Photos missing after restore"
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:
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:
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
Revision History
| Date | Version | Changes |
|---|---|---|
| 2026-02-13 | 1.0 | Initial documentation - two-tier backup strategy |
Last Updated: February 13, 2026
Review Schedule: Quarterly