added Immich
This commit is contained in:
@@ -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 |
|
| [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 |
|
| [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 |
|
| [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 |
|
| [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 |
|
| [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 |
|
| [overleaf](overleaf/) | 8020 | LaTeX editor. Four containers: app, Mongo (replica set), Redis, init |
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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>
|
||||||
@@ -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:
|
||||||
Reference in New Issue
Block a user