Kituwa IT · Self-hosting guides

Install Immich with Docker Compose

Self-hosted Google Photos replacement

photosbackupsface search

Immich is a Google Photos replacement: automatic phone backup, a timeline, albums, shared libraries, map view, and on-device object and face recognition. It is the single most popular self-hosted media app going, and the most likely to eat more disk than you planned for.

Category
Media & photos
License
AGPL-3.0
Needs
Postgres + Valkey
Image
immich-server

What it is

Your photos land on your disk, get indexed, and become searchable. It has real mobile apps that back up in the background, plus a web UI for the desktop library. A self-hosted ML container does recognition locally, so no photo ever leaves the house.

Before you start

  • Budget disk properly. Expect the original files plus thumbnails, a video-encoded proxy, and encoded stills. A 100 GB phone library can land anywhere between 150 and 300 GB.
  • The mobile app needs a reachable URL. If your server is only on a LAN, put it behind Tailscale, Cloudflare Tunnel, or a real domain.
  • Build the library root and the database on different physical disks. Putting both in the same ./ on one cheap SSD is the classic way to lose a decade of photos to one failure.

1 — Create the directories and the .env

Command / configuration
mkdir -p ~/services/immich/{db,upload,data,cache}
cd ~/services/immich

cat > .env <<'EOF'
DB_USERNAME=immich
DB_PASSWORD=CHANGE_ME
DB_DATABASE_NAME=immich
DB_DATA_LOCATION=./db
UPLOAD_LOCATION=./upload
IMMICH_MEDIA_LOCATION=./data
ML_CACHE_LOCATION=./cache
EOF

2 — Write the compose file

Command / configuration
services:
  immich-server:
    container_name: immich_server
    image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-latest}
    restart: always
    ports:
      - "2283:2283"
    environment:
      DB_HOSTNAME: immich_postgres
      DB_USERNAME: ${DB_USERNAME}
      DB_PASSWORD: ${DB_PASSWORD}
      DB_DATABASE_NAME: ${DB_DATABASE_NAME}
      REDIS_HOSTNAME: immich_redis
      IMMICH_MEDIA_LOCATION: ${IMMICH_MEDIA_LOCATION:-./data}
    volumes:
      - ${DB_DATA_LOCATION:-./db}:/var/lib/postgresql/data
      - ${UPLOAD_LOCATION:-./upload}:/usr/src/app/upload
      - ${IMMICH_MEDIA_LOCATION:-./data}:/usr/src/app/exthost
    depends_on:
      - immich_postgres
      - immich_redis
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:2283/api/server/ping"]
      interval: 1m
      timeout: 5s
      retries: 3
      start_period: 5m

  immich-machine-learning:
    container_name: immich_machine_learning
    image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-latest}
    restart: always
    volumes:
      - ${ML_CACHE_LOCATION:-./cache}:/cache
    environment:
      OMP_NUM_THREADS: 1

  immich_postgres:
    container_name: immich_postgres
    image: ghcr.io/immich-app/postgres:${IMMICH_VERSION:-latest}
    restart: always
    volumes:
      - ${DB_DATA_LOCATION:-./db}:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_DATABASE_NAME}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE_NAME}"]
      interval: 10s
      timeout: 5s
      retries: 5

  immich_redis:
    container_name: immich_redis
    image: valkey/valkey:8-bookworm
    restart: always
    command: redis-server --save "" --appendonly no
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

Recent Immich releases consolidated the old API/machine-learning/web split into a single immich-server image. If you're copying a 2024-era compose file it will pull images that no longer exist.

3 — Start it

Command / configuration
docker compose up -d
docker compose logs -f immich-server | grep -i "listening\|error"

4 — First-run setup

  1. Open http://yourhost:2283, register the first account. The first registered account becomes the admin — there is no separate admin flag, so register that account first.
  2. In Administration → Settings → Storage, set the library location and enable "External libraries" if you want to point at a NAS or an existing photo folder.
  3. Install the mobile app, then set Settings → Backup → Background backup to "All photos, including videos" and choose Wi-Fi-only if you're bandwidth-constrained.
  4. Run the first full job queue from Administration → Jobs and watch the throughput. It'll take a while on a cold library.

5 — Back it up properly

Command / configuration
docker exec -u postgres immich_postgres pg_dump -U immich immich > immich.sql
tar -czf immich-upload.tgz ./upload
docker exec immich_postgres pg_dumpall -U postgres > globals.sql
Read the version notes before every upgradeImmich runs schema migrations on boot. Never roll back to an older image after an upgrade — the migration is one-way and the older code will fail against the new schema. Snapshot the database before pulling a new tag, always.

Help when you need it

Want help getting this running?

We can help with a supported Linux host, application setup, migration or troubleshooting. Contact us to confirm the software, scope and scheduling before ordering.

Related guides

← Browse all 30 guides · Back to top