added Immich

This commit is contained in:
Goyban
2026-09-23 15:12:08 +02:00
parent 9355beaee2
commit 595c20a0a1
4 changed files with 239 additions and 0 deletions
+2
View File
@@ -46,6 +46,8 @@ handled separately — see [Exposing services](#exposing-services).
| [gluetun](gluetun/) | 9880 | VPN kill switch with qBittorrent + pyload-ng inside it, plus HTTP/SOCKS proxies |
| [heimdall](heimdall/) | 4080 | Dashboard / start page for the other services |
| [httpserver](httpserver/) | 8083 | Bare nginx file share. Plain HTTP on purpose — works with very old clients |
| [immich](immich/) | 2283 | Photo and video library with local ML search. Four containers, Postgres + VectorChord |
| [librespeed](librespeed/) | 3011 | Self-hosted speed test. Measures the path to your box, not your ISP |
| [jellyfin](jellyfin/) | 8096 | Media streaming. Also 7359/udp for auto-discovery |
| [openwebui](openwebui/) | 3033 | LLM chat UI. One `OWUI_TAG` switches between CPU, CUDA and bundled-Ollama |
| [overleaf](overleaf/) | 8020 | LaTeX editor. Four containers: app, Mongo (replica set), Redis, init |
+40
View File
@@ -0,0 +1,40 @@
# Copy to .env and adjust. .env is git-ignored; this file is not.
#
# Immich is the one stack here where .env is NOT optional: compose.yaml
# has `env_file: .env` on two services, so Compose refuses to start
# without the file existing. It is also the application's own config, not
# just a few variables Compose interpolates.
#
# This mirrors upstream's example.env for the pinned release. When you
# update compose.yaml, re-fetch this too:
# curl -fLO https://github.com/immich-app/immich/releases/latest/download/example.env
# ─── Storage ────────────────────────────────────────────────────────
# Your photos and videos. Mounted at /data inside the container -- do not
# change the container side, only this. This is the directory to back up.
UPLOAD_LOCATION=./library
# The Postgres data directory. Network shares (NFS/SMB) are NOT supported
# here and will corrupt the database; it must be local storage.
DB_DATA_LOCATION=./postgres
# ─── Version ────────────────────────────────────────────────────────
# Pin the MAJOR. Immich ships breaking changes between majors and the
# compose file changes with them, so leaving this unset (which resolves
# to `release`) means an unattended `docker compose pull` can jump a
# major and leave your compose file behind. See the README.
IMMICH_VERSION=v3
# ─── Database ───────────────────────────────────────────────────────
# Change this. Letters and digits only -- no special characters or
# spaces, they break the connection string.
# openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 32
DB_PASSWORD=
# ─── Optional ───────────────────────────────────────────────────────
# Uncomment and set to a tz identifier if the server clock isn't right.
#TZ=Europe/Paris
# ─── Leave these alone ──────────────────────────────────────────────
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
+121
View File
@@ -0,0 +1,121 @@
# Immich
Self-hosted photo and video library. Phone backup that runs on your own disk,
with the parts that make Google Photos worth using — face and object search,
places, memories, shared albums — done locally by a machine-learning container.
The heaviest stack in this repo: four containers, a Postgres with vector
extensions, and a model cache. Budget a few GB of RAM and expect the first
import to work the CPU hard.
## Quick start
```bash
cp .env.example .env
$EDITOR .env # UPLOAD_LOCATION, DB_DATA_LOCATION, DB_PASSWORD
docker compose up -d
```
Open `http://<host>:2283` and register. **The first account created is the
admin** — there is no separate bootstrap step, so do this before the port is
reachable by anyone else.
## Ports
| Port | Proto | Purpose |
|------|-------|---------|
| 2283 | http | Web UI, mobile app API, everything |
Postgres and Valkey are reachable only on the stack's internal network.
## Why it looks like this
**This file is upstream's, verbatim, and should stay that way.** Immich ships a
`docker-compose.yml` with each release, pins two of its images *by digest*, and
changes the file between versions — the mount path, the Postgres extension
build, added `shm_size`. Local edits turn every update into a three-way merge.
The repo convention of `${VAR:-default}` is deliberately **not** applied here for
the same reason: keeping it byte-identical to upstream means you can re-fetch and
`diff` to see exactly what a release changed.
```bash
curl -fLo /tmp/immich-new.yml \
https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
diff -u compose.yaml /tmp/immich-new.yml
```
Pinned at **v3.2.2** (released 2026-09-15).
**Four containers.** `immich-server` is the API and web UI. `immich-machine-learning`
runs the CLIP and face-detection models — it is separate because it is the part
you might want on a GPU, and because its model cache is a named volume rather
than something you back up. `database` is Postgres with **VectorChord**, which
is what makes similarity search possible; a stock Postgres image will not work.
`redis` is Valkey, the Redis fork, used as the job queue.
**`env_file: .env` is a hard dependency.** Unlike every other stack here, where
`.env` is optional because the compose file carries defaults, Compose will refuse
to start this one if the file does not exist.
**Images are digest-pinned** for Valkey and Postgres
(`@sha256:…`), so those two are byte-identical to what upstream tested against
this release. The Immich images themselves float on `${IMMICH_VERSION:-release}`
— which is why pinning `IMMICH_VERSION` in `.env` matters.
## Gotchas
- **Pin `IMMICH_VERSION` to a major.** Unset, it resolves to `release`, so a
routine `docker compose pull` can carry you across a major version while your
compose file stays behind. Upstream's own `example.env` now sets
`IMMICH_VERSION=v3` for exactly this reason.
- **The container media path changed, and it is easy to miss.** Older compose
files mount `${UPLOAD_LOCATION}:/usr/src/app/upload`; since **v1.140.0** it is
`${UPLOAD_LOCATION}:/data`, because `IMMICH_MEDIA_LOCATION` now defaults to
`/data`. Run a new image against an old compose file and the server looks for
your library at an unmounted path — it appears empty, and anything written
goes into the container and is lost when it is recreated. If you are adopting
this file over an older one, that mount line is the one to check first.
- **`DB_DATA_LOCATION` must be local storage.** Not NFS, not SMB, not a
network share of any kind. Postgres on a network filesystem corrupts, and
upstream says so in the example env.
- **Upgrading Postgres extensions is a real migration.** The image here is
`14-vectorchord0.4.3-pgvectors0.2.0`; moving from an older VectorChord build
makes Immich alter the database on first boot, which "can take seconds to
minutes". Back up `DB_DATA_LOCATION` before any version jump, and read
[the upgrade notes](https://docs.immich.app/install/upgrading/).
- **`shm_size: 128mb` on the database is load-bearing**, not decoration.
Postgres uses shared memory for larger queries and Docker's 64 MB default is
not enough here. Upstream's upgrade guide lists adding it as a required step.
- **`DB_STORAGE_TYPE: 'HDD'` is commented out** in the database environment.
Uncomment it if the Postgres data directory sits on a spinning disk — it tunes
the planner's assumptions about random reads. Leave it alone on SSD or NVMe.
- **Back up `UPLOAD_LOCATION` and `DB_DATA_LOCATION` together.** The files are
the photos; the database holds every album, face cluster, share and edit.
Either alone is most of a disaster.
- **The first import is expensive.** Machine learning runs over the whole
library once. On a low-power box expect it to saturate the CPU for hours —
the same caveat as [copyparty](../copyparty/README.md) on an N100, and worth
scheduling rather than discovering.
## Exposing it
The mobile apps talk to the same port as the browser, so whatever you put in
front has to work for both.
- [Reverse proxy with Caddy](../docs/reverse-proxy.md) — the normal route.
Raise the upload body limit or large videos fail on the way in.
- [Cloudflare Tunnel](../cloudflare-tunnel/) — **the ~100 MB body cap is exactly
the wrong limit for this.** A phone's 4K video will exceed it. Read
[the limits](../docs/cloudflare-tunnel.md) first.
- [Single sign-on with Authentik](../docs/authentik-sso.md) — Immich speaks OIDC
natively, so use that rather than forward auth, which would break every mobile
client. Keep a local admin account until the flow is proven.
## Links
- Install guide: <https://docs.immich.app/install/docker-compose>
- Release compose file: <https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml>
- Environment variables: <https://docs.immich.app/install/environment-variables>
- Upgrading: <https://docs.immich.app/install/upgrading/>
- Hardware-accelerated ML: <https://docs.immich.app/features/ml-hardware-acceleration>
- Compose builder: <https://immich.app/docker-compose-builder>
+76
View File
@@ -0,0 +1,76 @@
#
# WARNING: To install Immich, follow our guide: https://docs.immich.app/install/docker-compose
#
# Make sure to use the docker-compose.yml of the current release:
#
# https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
#
# The compose file on main may not be compatible with the latest release.
name: immich
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
# extends:
# file: hwaccel.transcoding.yml
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
volumes:
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
ports:
- '2283:2283'
depends_on:
- redis
- database
restart: always
healthcheck:
disable: false
immich-machine-learning:
container_name: immich_machine_learning
# For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag.
# Example tag: ${IMMICH_VERSION:-release}-cuda
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
# extends: # uncomment this section for hardware acceleration - see https://docs.immich.app/features/ml-hardware-acceleration
# file: hwaccel.ml.yml
# service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
healthcheck:
disable: false
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:9@sha256:70739f85ad2ee01a726a965584a0f94895f01b0c60b3cc8b0aeef11eaa6888cf
healthcheck:
test: redis-cli ping | grep -q PONG || exit 1
restart: always
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:bcf63357191b76a916ae5eb93464d65c07511da41e3bf7a8416db519b40b1c23
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:
# Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
shm_size: 128mb
restart: always
healthcheck:
disable: false
volumes:
model-cache: