Ditch the Cloud, Keep the Memories: An Immich Self-Hosting Playbook
Google Photos charges you rent for your own memories. Immich gives you the same magic — face recognition, smart search, map view, instant phone backup — running on hardware you actually own.
The math that got me off Google Photos
A 200 GB Google One tier costs roughly $3 a month, forever. A 4 TB spinning drive costs about $80, once. If your photo library is the average family's 150–300 GB, the break-even point on a self-hosted setup lands somewhere around month two. After that, every additional gigabyte is free, and — the part that actually matters — nobody is scanning your kid's birthday photos to tune an ad model.
But let's be honest about why most people don't self-host their photos: it's not the price of the drive. It's that the free options historically sucked. Resilio, Piwigo, Lychee — fine tools, none of them a drop-in Google Photos replacement. Immich is the first one that feels like the real thing: same auto-upload from your phone, same "show me every photo of my dog at the beach," same timeline that doesn't lag on 80,000 assets. The difference is the server lives under your desk (or on a $4 VPS with a fat disk attached), and the source code is yours to audit.
The honest requirements (read this before you deploy)
Immich is not a lightweight PHP gallery. It's a multi-service stack — server, machine learning, PostgreSQL with a vector extension, Redis, microservices — and it has opinions about your hardware:
- RAM: 4 GB is the floor, 8 GB is comfortable. The ML jobs (facial recognition, CLIP semantic search) eat memory. Running the official compose on a 2 GB box will technically boot, then die the moment it starts chewing through 10,000 thumbnails.
- CPU: Fine for the web UI, but video transcoding on import is CPU-hungry. An Intel box with Quick Sync (VAAPI/QSV passthrough) turns overnight transcode queues into background noise.
- Disk: Your library size plus ~20% for thumbnails and encoded previews. Plan the upload volume now, not later.
- PostgreSQL 16 with pgvecto.rs — this ships in the official compose file, don't swap in your own Postgres unless you enjoy pain.
- Backups: YOUR job. Google does disaster recovery so you don't have to. The moment you self-host, you are the SRE. If you don't have a backup plan, you don't have a photo library — you have a ticking data-loss incident. (More on the drill below.)
Minimum sane setup: a small VPS with attached block storage, a home NAS, or a mini PC. For a few-thousand-photo library, a Raspberry Pi 5 with an external SSD gets it done — just expect slower face-recognition runs.
The deploy: fifteen minutes with Docker Compose
Immich publishes an official compose file and keeps it current. Don't grab a random third-party compose from a blog (yes, including this one for the compose file itself) — use the official release:
mkdir -p ~/immich && cd ~/immich
curl -o docker-compose.yml https://raw.githubusercontent.com/immich-app/immich/main/docker/docker-compose.yml
curl -o .env https://raw.githubusercontent.com/immich-app/immich/main/docker/example.env
Edit .env and set two things: a strong DB_PASSWORD, and UPLOAD_LOCATION pointing at your big disk. Then:
docker compose up -d
docker compose logs -f
First boot downloads the machine-learning models — anywhere from 500 MB to 2 GB. It looks like the container is stuck. It's not. Watch the logs, make coffee, and open the web UI at http://your-server:2283 when the ML container settles. The first account you register becomes the admin. Done — you have Google Photos, minus Google.
Expose it safely (this part is not optional)
Your photos are the most personal data you own. Exposing Immich to the internet without TLS is malpractice. Two sane routes:
- Reverse proxy (Nginx or Caddy): point a subdomain at it, terminate TLS with Let's Encrypt. If you use Nginx, don't forget the websocket headers — the Immich mobile app's "server unreachable" error is almost always a missing
Upgrade/Connectionproxy header, not a real network problem:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
- Cloudflare Tunnel: zero open ports on your router, TLS handled for you, and you get free DDoS scrubbing. My preferred option for a home server.
Don't skip this step "temporarily." Temporary HTTP exposure has a way of becoming permanent.
Phone backup that actually works
The iOS and Android apps are where Immich earns its keep. Install, point at your server, enable auto-upload. Two caveats from real-world use:
- iOS background backup is flaky — Apple's background execution limits mean you should open the app before bed for the first few weeks while it backfills your camera roll. After the initial sync, deltas are small and painless.
- Existing libraries can be mounted read-only via External Libraries. Got 40,000 photos on a NAS? Mount the folder, let Immich scan and index it without moving a single file. This is the feature that lets you try Immich without committing to a migration.
Once the backfill finishes, the experience is uncanny: search "beach 2024," tap a face cluster to name it once, and it tags everyone forever after — all on your hardware.
The gotchas nobody tells you
- The first boot looks broken. ML model downloads take 10–30 minutes on a normal connection. Watch logs, not vibes.
- Transcode queue on bulk import. Dump 50,000 photos in and the server spends a weekend generating thumbnails. Import in chunks, or just let it cook overnight — it's a one-time cost.
- Never auto-update with Watchtower. Immich releases sometimes require database migrations (especially the pgvecto.rs/Postgres side). The official release notes spell out the upgrade path — read them, then
docker compose pull && docker compose up -d. - Disk growth is sneaky. Previews and encoded videos add up. Run
docker system dfand check your upload volume monthly. Set an alert at 80% full — photos keep coming and a full disk corrupts uploads mid-write. - Keep your library portable. The
UPLOAD_LOCATIONdirectory plus a Postgres dump is your whole world. Never delete the database thinking the files are enough — the database is the library; the files are just the raw assets.
The backup drill (do this on day one)
Backups for Immich are two things, both scripted:
#!/bin/sh
# nightly Immich backup — cron this at 2 AM
BACKUP_DIR=/mnt/backups/immich
docker compose exec -T database pg_dump -U postgres immich > "$BACKUP_DIR/immich-$(date +%F).sql"
rsync -a --delete ~/immich/upload/ "$BACKUP_DIR/upload/"
Keep 7 daily dumps, 4 weekly rsync snapshots, and one copy off-site (a cheap S3-compatible bucket or a drive at a relative's house). Test a restore into a scratch compose stack once a quarter. An untested backup is a prayer, not a plan.
The verdict
Immich is the first self-hosted photo app that doesn't ask you to lower your standards. It's a real stack with real hardware requirements, and it hands you real responsibility for backups. In exchange, you get a Google Photos experience with zero subscription, zero surveillance, and a library that works identically whether you have 500 photos or 500,000. If you're already self-hosting anything — a media server, a VPN endpoint, a NAS — Immich is the easiest "why did I wait" deploy on the list.
Sources: Immich official documentation (docs.immich.app), Immich GitHub repository releases and upgrade notes (github.com/immich-app/immich).
Reader feedback
Was this article helpful?
0 people found this article helpful.
