#!/bin/bash # Immich Postgres Database Backup Script # This script creates a # Check if the Postgres container exists and is running echo "Checking postgres container status..." if ! docker ps -q --filter "name=immich_postgres" | grep -q .; then echo "Error: immich_postgres container is not running. Cannot proceed with backup." exit 1 fi echo "Taking database backup using pg_dumpall as recommended by Immich documentation..." # Use pg_dumpall with recommended flags: --clean and --if-exists docker exec -t immich_postgres pg_dumpall \ --clean \ --if-exists \ --username="${DB_USERNAME}" \ > "${BACKUP_PATH}" 2>/tmp/pg_dumpall_error.log # Check if the dump was successful the Immich Postgres database # Based on recommendations from https://immich.app/docs/administration/backup-and-restore/ # Set up error handling set -e # Function to ensure server is unpaused even if script fails cleanup() { local exit_code=$? echo "Running cleanup..." # Check if immich_server is paused and unpause it if needed if [ "${IMMICH_SERVER_RUNNING:-true}" = true ] && docker inspect --format='{{.State.Status}}' immich_server 2>/dev/null | grep -q "paused"; then echo "Unpausing immich_server container during cleanup..." docker unpause immich_server 2>/dev/null || true fi if [ $exit_code -ne 0 ]; then echo "Script failed with exit code $exit_code" fi exit $exit_code } # Set up trap to call cleanup function on script exit (normal or error) trap cleanup EXIT SIGINT SIGTERM # Load environment variables from the .env file ENV_FILE="$(dirname "$0")/.env" if [ -f "$ENV_FILE" ]; then echo "Loading environment variables from $ENV_FILE" source "$ENV_FILE" else echo "Error: .env file not found in $(dirname "$0")" exit 1 fi # Verify required environment variables are set if [ -z "$DB_USERNAME" ] || [ -z "$DB_DATABASE_NAME" ]; then echo "Error: Required environment variables (DB_USERNAME, DB_DATABASE_NAME) not found in .env file" exit 1 fi # Initialize container status variables IMMICH_SERVER_RUNNING=true # Create backup directory if it doesn't exist BACKUP_DIR="$(dirname "$0")/database_backups" mkdir -p "$BACKUP_DIR" # Generate timestamp for the backup filename TIMESTAMP=$(date +"%Y%m%d_%H%M%S") BACKUP_FILENAME="immich_db_backup_${TIMESTAMP}.sql" BACKUP_PATH="${BACKUP_DIR}/${BACKUP_FILENAME}" echo "Starting backup of Immich Postgres database..." echo "Using database settings from .env file:" echo " - Database: ${DB_DATABASE_NAME}" echo " - Username: ${DB_USERNAME}" echo " - Container: immich_postgres" # Check if the Immich server container exists and is running echo "Checking immich_server container status..." if docker ps -q --filter "name=immich_server" | grep -q .; then echo "Pausing immich_server container to minimize database writes..." if ! docker pause immich_server; then echo "Failed to pause immich_server container." # Continue with backup instead of exiting fi else echo "Note: immich_server container not found or not running. Continuing with backup anyway." # Set a flag so we don't try to unpause it later IMMICH_SERVER_RUNNING=false fi echo "Taking database backup using pg_dumpall as recommended by Immich documentation..." # Use pg_dumpall with recommended flags: --clean and --if-exists docker exec -t immich_postgres pg_dumpall \ --clean \ --if-exists \ --username="${DB_USERNAME}" \ > "${BACKUP_PATH}" # Check if the dump was successful if [ $? -ne 0 ] || [ ! -s "${BACKUP_PATH}" ]; then echo "Error: Database backup failed or created an empty file." if [ -f "/tmp/pg_dumpall_error.log" ]; then echo "Error details:" cat /tmp/pg_dumpall_error.log rm /tmp/pg_dumpall_error.log fi exit 1 fi # Clean up error log if it exists rm -f /tmp/pg_dumpall_error.log # Compress the backup file echo "Compressing backup file..." if ! gzip -f "${BACKUP_PATH}"; then echo "Warning: Failed to compress backup file." fi # Resume the Immich server only if it was running and we paused it if [ "${IMMICH_SERVER_RUNNING:-true}" = true ]; then echo "Resuming immich_server container..." if ! docker unpause immich_server 2>/dev/null; then echo "Note: No need to unpause immich_server container." fi fi echo "Backup completed successfully!" echo "Backup saved to: ${BACKUP_PATH}.gz" # Optional: List backups and show total size echo -e "\nBackup information:" find "${BACKUP_DIR}" -name "*.gz" | wc -l | xargs echo "Total number of backups:" du -sh "${BACKUP_DIR}" | cut -f1 | xargs echo "Total backup size:" # Optional: Check if backup file is smaller than expected (potential warning) BACKUP_SIZE=$(du -k "${BACKUP_PATH}.gz" | cut -f1) if [ ${BACKUP_SIZE} -lt 100 ]; then echo "Warning: Backup file is smaller than expected (${BACKUP_SIZE}KB). Please verify its integrity." fi # Optional: Remove backups older than 30 days # find "${BACKUP_DIR}" -name "immich_db_backup_*.sql.gz" -mtime +30 -delete echo -e "\nTo restore this backup, follow the instructions at: https://immich.app/docs/administration/backup-and-restore/"