Planning Your Homelab named photo backup as one of the most common reasons people start a homelab in the first place. Vaultwarden showed how satisfying it feels to replace a paid cloud service with one you run yourself - Immich is the same trade for photos.

What Immich actually is

Immich is a self-hosted photo and video backup app modeled closely on Google Photos: mobile apps for iOS/Android with automatic background upload, timeline browsing, albums, and (optionally) face recognition and object/scene search - all running against your own storage instead of Google's.

Running it

Immich ships as several containers working together, not one - more moving parts than anything else in this tier, but the official install script handles the wiring for you.

services:
  immich-server:
    image: ghcr.io/immich-app/immich-server:release
    container_name: immich-server
    ports:
      - "2283:2283"
    volumes:
      - ./library:/usr/src/app/upload
    environment:
      - DB_HOSTNAME=immich-postgres
      - DB_USERNAME=immich
      - DB_PASSWORD=${DB_PASSWORD}
      - DB_DATABASE_NAME=immich
      - REDIS_HOSTNAME=immich-redis
    depends_on:
      - immich-postgres
      - immich-redis
    restart: unless-stopped

  immich-machine-learning:
    image: ghcr.io/immich-app/immich-machine-learning:release
    container_name: immich-machine-learning
    volumes:
      - ./model-cache:/cache
    restart: unless-stopped

  immich-redis:
    image: docker.io/valkey/valkey:9
    container_name: immich-redis
    restart: unless-stopped

  immich-postgres:
    image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
    container_name: immich-postgres
    environment:
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_USER=immich
      - POSTGRES_DB=immich
    volumes:
      - ./pgdata:/var/lib/postgresql/data
    restart: unless-stopped
  • Image tags and the exact service list change faster here than for most self-hosted apps in this guide - use Immich's official docker-compose.yml and .env from their install docs as your actual starting point, rather than copying the above verbatim. In particular, the Postgres image tag is version-pinned to a specific vector-extension build (the string after postgres: above) that changes with Immich releases - check the current tag before pulling, a stale one will simply fail to pull.
  • immich-server's DB_USERNAME/DB_PASSWORD/DB_DATABASE_NAME must match the immich-postgres service's POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DB below exactly - a mismatch here is a common first-run failure (immich-server can't authenticate to its own database) that shows up as the server container looping on restart.
  • immich-machine-learning is what powers face grouping and "search for 'beach'" style queries. It's the one optional-feeling piece - see the resource note below.

Resource expectations: the server, Redis, and Postgres together are light - comparable to Vaultwarden. Machine learning is the real cost: budget at least 2 extra CPU cores and 2-4GB RAM while it's actively indexing a new library, tapering off once your existing photos are processed. A modest mini PC handles this fine for a household's library; it's just noticeably busier during the first big import.

Mobile app auto-upload

Install the Immich app, point it at http://server-ip:2283, log in, and enable background backup. This is the entire point of running Immich instead of just dropping files in a folder - your phone's photos land on your own server automatically, same as they would with a cloud service, without you doing anything after the initial setup.

Same caveat as Vaultwarden applies here: the mobile app works fine over plain HTTP on your home Wi-Fi, but background upload while you're out and about needs either the VPN approach from Remote Access (Intermediate) or a properly TLS-terminated reverse proxy - both out of scope until then. Until you're there, uploads simply queue on the phone and catch up whenever it's back on your home network, which is a perfectly reasonable place to leave things for now.

Backing it up

Two things matter here, and together they're bigger than a typical service's ./data folder:

  • The Postgres database - metadata: albums, face tags, sharing links. Small, but without it the library folder is just a pile of unsorted files.
  • The ./library folder - the actual photos and videos. This is the one exception to Backups 101's "you don't need to back up everything" guidance: this content usually is genuinely irreplaceable, unlike a media library you could re-rip or re-download.

Include both in the backup scope you set up in Backups 101, and treat this as the single highest-priority thing on this machine to get right - a lost, un-backed-up photo library is a different category of loss than a lost service you can just reinstall.

Notes and documents, if those were on your list too

Planning Your Homelab grouped "note-taking, photo backup, media streaming" together as common motivations. Photos and streaming now have real answers (Immich, and Jellyfin from First Services). If note-taking or scanned-document storage was also on your list, the good news is it's the same pattern again, not a new one to learn: Paperless-ngx for scanned documents and receipts (it OCRs and tags them automatically), or a lightweight self-hosted notes app like Trilium or a Joplin Server sync target. Each is a single container plus a bind-mounted data folder, same shape as everything else in this tier - not detailed here because there's genuinely nothing more to explain beyond what you've already done twice.

Next: File Sync with Nextcloud.