# Verified compose for Immich (no machine learning, 2 GiB cap), tested 2026-10-02 by the SelfHostBench lab. # Lab host: Intel(R) Xeon(R) Processor @ 2.10GHz, 4 vCPU, 15.7 GiB RAM, x86_64, Docker 29.6.2. # Floating image tags below were replaced by the version resolved at test time; # the registry digest is in the comment on each image line. # Measurements: immich-no-ml-2g.json (schema 2). # Companion env file: immich-no-ml-2g.env (save it as .env next to this file). # Secrets are not published: the lab's values are public. In immich-no-ml-2g.env: # DB_PASSWORD=CHANGE_ME_DB_PASSWORD. Replace it with your own before the first start. # Immich: self-hosted photo and video library (this variant: machine learning disabled). # # Based on the compose file of the current Immich release: # https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml # Changes from the release file (everything else is as shipped): # * the upload and database folders are named volumes instead of the ./library and # ./postgres bind mounts, so the stack can run on a remote Docker host and `down -v` # leaves nothing behind. Use bind mounts (UPLOAD_LOCATION / DB_DATA_LOCATION in .env) # if you want photos in a folder you can see. # * the extends/hardware-acceleration comments are removed (not tested here). # Put DB_PASSWORD and friends in the .env file next to this file. # # VARIANT (SelfHostBench lab): no machine learning (see apps/immich-no-ml) plus a hard memory cap per container. # The caps add up to 2048 MiB (2 GiB), our stand-in for "a 2 GB machine": # immich-server 1344m + database 640m + redis 64m = 2048m # Splits tried (server + database + redis, all in MiB; lab/notes/immich-memory-caps-2026-10-01.md, section 4, # and lab/notes/methodology-change-2026-10-02.md, section 4.1): # 1472 + 512 + 64: failed on Oct 1. Postgres was OOM-killed while the server imported its geodata on # first start, and the server exited. # 1216 + 768 + 64: failed on Oct 1. The server was OOM-killed while starting and restarted once. # 1344 + 640 + 64: this file. It worked on Oct 1 and in 3 of 8 runs on Oct 2; in the other 5 runs on # Oct 2 Postgres was OOM-killed on first start (the same failure as the first split). # So this split works only sometimes. # `mem_limit` is a hard limit: a container that goes over it is OOM-killed. name: immich services: immich-server: container_name: immich_server mem_limit: 1344m image: ghcr.io/immich-app/immich-server:v3.2.4 # sha256:d317916b28090c33eb36b308464ea391f8b7df1d850fcfea227a39ec879718c2 (version v3.2.4, from label:org.opencontainers.image.version) volumes: # Originals, thumbnails, encoded video. This is your photo library: back it up. - immich-upload:/data - /etc/localtime:/etc/localtime:ro env_file: - .env ports: - '2283:2283' depends_on: - redis - database restart: always healthcheck: disable: false redis: container_name: immich_redis mem_limit: 64m image: docker.io/valkey/valkey:9@sha256:70739f85ad2ee01a726a965584a0f94895f01b0c60b3cc8b0aeef11eaa6888cf # version 9.1.1 (from exec); no registry tag for it could be verified, so the digest is pinned instead healthcheck: test: redis-cli ping | grep -q PONG || exit 1 restart: always database: container_name: immich_postgres mem_limit: 640m image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0 # sha256:bcf63357191b76a916ae5eb93464d65c07511da41e3bf7a8416db519b40b1c23 (version 14-vectorchord0.4.3-pgvector0.8.1-pgvectors0.2.0, from label:org.opencontainers.image.version) environment: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_USER: ${DB_USERNAME} POSTGRES_DB: ${DB_DATABASE_NAME} POSTGRES_INITDB_ARGS: '--data-checksums' # Uncomment the DB_STORAGE_TYPE: 'HDD' var if your database isn't stored on SSDs # DB_STORAGE_TYPE: 'HDD' volumes: # The Immich database (albums, users, search index). Back this up with pg_dump. - immich-db:/var/lib/postgresql/data shm_size: 128mb restart: always healthcheck: disable: false volumes: immich-upload: immich-db: