Netgrimoire/immich_backup.md
2026-02-14 03:16:21 +00:00

489 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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 <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_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 <config-snapshot-id> /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 <snapshot-id> /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