Jake Groszewski

Blog

Self-Host Immich: Run Your Own Private Photo Library as a Google Photos Alternative

Google Photos is convenient until you actually think about what you're handing over: every photo, every location tag, every face scan, stored on infrastructure you don't control. When Google quietly dropped unlimited free storage in 2021, a lot of people started looking for alternatives. Immich is the best one I've found, and it's grown fast enough that the "self-hosted" stigma of clunky interfaces and missing features doesn't really apply anymore.

This guide walks through deploying Immich on a Linux server, importing an existing phone photo archive, and setting up backups that make the library durable over time.

What Immich Actually Is

Immich is an open-source photo and video management server with a mobile app for both iOS and Android. You get automatic background upload from your phone, facial recognition, location-based albums, a map view, and a search bar that understands natural language queries. The web interface is clean enough that non-technical family members can use it without complaints.

The project moves quickly. Check the release notes before upgrading because breaking changes do happen, especially between minor versions. That's a manageable tradeoff for getting full ownership of your data.

Server Requirements

Immich runs via Docker Compose, which keeps the setup fairly portable. You need:

  • A Linux host (Ubuntu 22.04 or Debian 12 work well)
  • At least 4 GB of RAM; 8 GB is more comfortable when machine learning features are enabled
  • Storage sized to your library (photos compress well, but 4K video adds up fast)
  • Docker and Docker Compose installed

A Raspberry Pi 4 can technically run Immich but the ML features will be slow. A used mini PC or a VPS with attached block storage is a more practical choice for most people.

Deploying Immich

Pull the official Docker Compose file and environment template:

mkdir ~/immich && cd ~/immich
wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env

Open .env and set the two variables that matter most:

# .env
UPLOAD_LOCATION=/mnt/photos/immich
DB_PASSWORD=your_strong_password_here

UPLOAD_LOCATION points to wherever your storage is mounted. If you have an external drive or network-attached storage, put the path here rather than somewhere inside your OS disk.

Bring everything up:

docker compose up -d

Immich will pull several images (the main server, the machine learning container, Redis, and Postgres) and start listening on port 2283. Navigate to http://your-server-ip:2283 to create your admin account.

For production use, put Nginx or Caddy in front of Immich with a TLS certificate. Caddy makes this nearly trivial:

photos.yourdomain.com {
    reverse_proxy localhost:2283
}

Run caddy reload and you have HTTPS with automatic certificate renewal.

Importing an Existing Photo Archive

The mobile app handles ongoing uploads, but if you have years of photos sitting on a hard drive or exported from Google Takeout, you'll want to bulk-import them.

Immich provides a CLI tool for this:

npx @immich/cli login https://photos.yourdomain.com your@email.com yourpassword
npx @immich/cli upload --recursive /path/to/your/photo/archive

The CLI reads EXIF data to preserve original timestamps and skips duplicates based on file hash, so running it multiple times on the same folder is safe. For a Google Takeout export, the JSON sidecar files that Google includes will be parsed to recover metadata that gets stripped from the image files themselves.

A 50 GB archive of 20,000 photos typically takes 30-90 minutes depending on your network and how busy the ML container is with generating embeddings. You can watch progress in the admin panel under Jobs.

Setting Up the Mobile App

Install the Immich app from the App Store or Google Play, point it at your server URL, and log in. Under Settings, enable background backup and choose your backup frequency. You can set it to upload only on Wi-Fi, which is the sensible default for most people.

The app will show a sync status in the top bar and a backup queue you can monitor. New photos hit the server within a few minutes of being taken when conditions are right.

Backups: The Part People Skip

Running your own server means you're also responsible for not losing your data. Immich itself is not a backup strategy. A self-hosted photo library with no offsite backup is worse than Google Photos in terms of data safety, not better.

The two things you need to back up:

  1. The UPLOAD_LOCATION directory (your actual photos and videos)
  2. The Postgres database (metadata, albums, faces, everything that makes the photos searchable)

For the database, dump it on a schedule:

#!/bin/bash
# /usr/local/bin/immich-db-backup.sh
DATESTAMP=$(date +%Y%m%d_%H%M%S)
docker exec immich_postgres pg_dumpall -U postgres > /mnt/backups/immich_db_${DATESTAMP}.sql
# Keep only the last 7 dumps
find /mnt/backups -name 'immich_db_*.sql' -mtime +7 -delete

Add that to cron to run nightly:

crontab -e
# Add:
0 2 * * * /usr/local/bin/immich-db-backup.sh

For offsite backup, rclone syncs both the photo directory and database dumps to any S3-compatible storage, Backblaze B2, or Google Drive. Backblaze B2 is cheap at around $6 per terabyte per month and the free egress to Cloudflare Workers is handy if you ever need to restore from a different location.

rclone sync /mnt/photos/immich b2:your-bucket-name/immich-photos --transfers 4
rclone sync /mnt/backups b2:your-bucket-name/immich-db-backups

Run both via cron after the database dump completes. Three to four in the morning is a reasonable window.

Ongoing Maintenance

Immich updates frequently. The recommended upgrade path is:

cd ~/immich
docker compose pull
docker compose up -d

Always read the release notes at https://github.com/immich-app/immich/releases before pulling a new version. Occasionally a migration requires running a specific command or waiting for a database job to finish before the UI becomes responsive again.

The machine learning features (face clustering, CLIP-based search) run as background jobs. On modest hardware they can take hours to process a large import, but they run at low priority and don't block normal use while working through the queue.

Closing Thought

Immich won't replace Google Photos for everyone. If you're sharing photos with family members who will absolutely not install an unfamiliar app, the friction is real. But for personal libraries, the combination of full data ownership, no monthly fee beyond storage costs, and an interface that's actually pleasant to use makes it the right call. The setup described here takes about an hour, and the result is a photo library that you actually control.