New releases
Recipe version compared with the latest known upstream release. A version number, not a reading of what changed.
Editorial pickPhotos and video
Immich keeps your photos and videos on your own server, uploads them automatically from your phone, and shows a familiar timeline with albums, a map, and content-based search. This recipe brings up the server, machine learning, PostgreSQL with vector search, and Valkey from one Compose file.
Immich is a photo archive for your own server that reproduces the familiar cloud gallery workflow: the Android and iOS apps upload photos and videos automatically, and the web interface shows a timeline by date, albums, a map, memories, and link sharing. It fits a family leaving Google Photos or iCloud, and a photographer who needs an archive without storage tiers.
A separate machine learning container adds content-based search without manual tags, face recognition, duplicate detection, and text recognition. All of it runs on your server: the photos never leave it.
The recipe brings up four containers — the server, machine learning, PostgreSQL
14 with vector extensions, and Valkey. Originals, thumbnails, and transcodes live
in a host directory, the database in a Docker volume. The reliable level is
declared partial: the database is a separate service and every container has a
healthcheck, but the recipe sets no resource limits and adds no external
monitoring.
Immich is under active development and still ships breaking changes regularly. Read the release notes and take a backup before every update.
The containers run without privileged, host networking, or Docker socket
access, and use no-new-privileges; only the web port is published, and only on
127.0.0.1. PostgreSQL and Valkey are reachable only inside the Compose network.
Immich has no public sign-up: the administrator creates accounts.
A photo archive is sensitive data: geotags, faces, the shape of your daily life.
Expose Immich over HTTPS only, enable two-factor authentication, update the
images promptly, and encrypt copies that leave the server. The PostgreSQL
password sits in .env next to the recipe — keep the file at mode 600 and out
of Git. The recipe sets no CPU or memory limits, so on a small server machine
learning jobs can starve the other services; add deploy.resources or disable
machine learning if that matters.
The immich-server and immich-machine-learning images are scanned with
Trivy; the result and the CVE list are shown on the card. Valkey and PostgreSQL
are pinned by digest and their tags do not follow the application version, so
they are outside the automated check — update them together with the upstream
Compose file.
These are stored results of separate checks, not real-time data. An unknown status means the check has not been performed yet.
Recipe version compared with the latest known upstream release. A version number, not a reading of what changed.
Result of a dedicated Docker image scan, not a Compose configuration check.
A new major version is found by comparing version numbers. A compatibility verdict is entered by hand after reading the release notes and the migration steps.
Upstream Compose changes relative to the verified recipe.
Pinned image tags checked for newer versions.
From observation to action
The recipe already pins the latest known release. The steps below show the evidence retained for that version.
v3.1.0v3.1.0Open this release on GitHub ↗ The link is evidence to review, not proof of compatibility.
The version numbers do not cross a major compatibility boundary. No compatibility verdict has been recorded.
No image-tag change is currently planned.
Migration, majors cannot be skipped. Release-specific migration steps still come from the release notes and installation guide.
No version change is currently planned. The recipe includes a backup procedure. Restore has been tested.
An exact Fully verified check for this target was recorded on 2026-08-30.
The status shows how fully the published recipe meets each level's requirements.
A minimal setup for a local network or access through a VPN.
The recipe covers every requirement at this level.
A public deployment with protected access and backups.
The recipe covers every requirement at this level.
A setup designed for predictable operations and observability.
You still need to add: external monitoring, cpu and memory limits.
Tailored to your server
Answer five questions and download a ready-to-run Immich bundle.
Screenshots have not been added yet.
Read the full guide first: it explains external access, backups, and data locations.
cp .env.example .envdocker compose up -ddocker compose psUpstream requires at least 2 CPU cores and 6 GB of RAM and recommends 4 cores and 8 GB. Budget disk space for the library plus 10–20 % for thumbnails and transcodes: this recipe stores both originals and generated files. You need Ubuntu 22.04+ or Debian 12+ with Docker Engine and Docker Compose v2.24+.
docker --version
docker compose version
nproc && free -m && df -h /srv
Since v3 the machine learning container on amd64 requires the x86-64-v2 microarchitecture level. Check it before installing:
/usr/bin/ld.so --help | grep -m1 x86-64-v2
If the line is missing, the ML container will not start: on such a server your only option is to disable machine learning and lose smart search and face recognition.
Put the recipe files in their own directory and create a private .env:
mkdir -p ~/services/immich
cd ~/services/immich
cp .env.example .env
chmod 600 .env
IMMICH_VERSION pins the version of every Immich image; IMMICH_PORT sets the
local port; IMMICH_UPLOAD_LOCATION is the host directory holding originals,
thumbnails, transcodes, and automatic database dumps; IMMICH_DB_VOLUME and
IMMICH_MODEL_CACHE_VOLUME name the Docker volumes for PostgreSQL and the model
cache; IMMICH_DB_USERNAME, IMMICH_DB_DATABASE_NAME, and IMMICH_DB_PASSWORD
configure database access; TZ sets the time zone.
Always replace the database password and point the library at a disk with free space:
sed -i "s|^IMMICH_DB_PASSWORD=.*|IMMICH_DB_PASSWORD=$(openssl rand -hex 24)|" .env
sudo mkdir -p /srv/immich/library
sed -i "s|^IMMICH_UPLOAD_LOCATION=.*|IMMICH_UPLOAD_LOCATION=/srv/immich/library|" .env
The password may contain only A-Za-z0-9. It cannot be changed after the first
start without recreating the database, so set it now.
Keep the port on localhost only and start the stack:
docker compose pull
docker compose up -d
docker compose ps
ssh -L 2283:127.0.0.1:2283 user@server.example
The first start takes longer than usual because the server applies database
migrations. Open http://localhost:2283, create an account — the first one
becomes the administrator — and complete the setup wizard. Immich has no public
sign-up: the administrator creates other users under Administration → Users.
The Android and iOS apps connect to the same address and add background upload of new photos.
On a VPS keep the 127.0.0.1 bind, block port 2283 from outside, and publish the
service only through an HTTPS reverse proxy. Check the stack and the API:
docker compose up -d
docker compose ps
curl --fail http://127.0.0.1:2283/api/server/ping
All four containers must report healthy. Machine learning downloads its models
on the first job, so CPU usage is high for the first minutes after an upload —
that is expected.
Without TLS use an SSH tunnel or a VPN. If the reverse proxy runs on another host
in a trusted LAN, replace 127.0.0.1 in compose.yaml with the server’s LAN
address and restrict the port to the proxy address in the firewall. Do not
publish Immich on 0.0.0.0 without network restrictions: access to the timeline
means access to the whole photo archive and its geotags.
Replace photos.example.com with your single domain in the file you pick from
proxy/. proxy/Caddyfile obtains a certificate automatically;
proxy/nginx.conf expects a Certbot certificate; proxy/traefik.yaml uses the
letsencrypt resolver. For Traefik in a container, replace 127.0.0.1 with a
host gateway it can reach.
All three samples lift the request body size limit and raise timeouts: without that, video uploads from a phone break. Verify the external endpoint:
curl --fail https://photos.example.com/api/server/ping
chmod +x backup.sh restore.sh
./backup.sh
The script stops immich-server and immich-machine-learning, takes a
PostgreSQL dump with pg_dump, archives the library directory, and starts the
containers again. Upstream considers copying the PostgreSQL data directory
instead of a dump unsafe, so this recipe always uses a dump.
The archive holds originals, thumbnails, and the whole database with metadata and
faces: encrypt it and keep at least one copy off the server. Immich also writes
automatic database dumps to UPLOAD_LOCATION/backups — daily at 02:00 keeping
the last 14 by default; they do not replace a copy of the files.
Restoring replaces both the database and the library directory:
./restore.sh ./backups/immich-YYYYMMDDTHHMMSSZ.tar
docker compose ps
curl --fail http://127.0.0.1:2283/api/server/ping
Before replacing anything the script takes a safety copy of the current data, then removes the database volume and loads the dump into a clean database. That is an upstream requirement: a dump must not be restored over a schema the server has already used. The database and the files must come from the same snapshot, otherwise the timeline will show entries without files.
Take a backup and read the release notes: Immich regularly ships changes that
require manual steps. Change only the pinned IMMICH_VERSION, then run:
./backup.sh
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 immich-server
Upgrade one version at a time and do not skip major releases: database migrations assume an upgrade from the previous version.
Immich database migrations are irreversible. Starting an older image against a
database already migrated by a newer version makes the server fail to start.
Restore the pinned IMMICH_VERSION in .env and restore the archive you created
before the update:
docker compose pull
./restore.sh ./backups/immich-before-update.tar
docker compose ps
Photos uploaded after the update are not in that archive. Copy them out of
UPLOAD_LOCATION separately before rolling back if you need them.
docker compose down removes the containers but keeps the database and the
library. Complete, irreversible removal after verifying a backup:
docker compose down
docker volume rm immich-database immich-model-cache
sudo rm -rf /srv/immich/library
rm -rf ~/services/immich
Sources: requirements, Docker Compose install, environment variables, backup and restore, and reverse proxy.
docker compose ps
docker compose logs --tail=200 immich-server
docker compose logs --tail=100 database
docker inspect --format '{{json .State.Health}}' "$(docker compose ps -q immich-server)"
immich-server will not start until the database passes its healthcheck. If the
database dies right after startup, the usual cause is volume permissions or a
changed IMMICH_DB_PASSWORD against an existing database: the password is set at
initialization and is not changed by the variable afterwards.
On amd64, since v3 the image needs the x86-64-v2 microarchitecture level:
/usr/bin/ld.so --help | grep -m1 x86-64-v2
docker compose logs --tail=100 immich-machine-learning
If it is unsupported, turn machine learning off under Administration → Settings →
Machine Learning and remove the service from compose.yaml. Smart search, face
recognition, duplicate detection, and OCR will not work in that case.
The limit comes from the reverse proxy, not from Immich. Nginx needs
client_max_body_size 0 and raised proxy_read_timeout and
proxy_send_timeout, Caddy needs request_body max_size, and Traefik needs the
buffering middleware with maxRequestBodyBytes: 0. All three samples in
proxy/ already carry these settings.
Besides originals, Immich stores thumbnails and transcoded videos. Check what takes the space:
sudo du -sh /srv/immich/library/*
docker system df -v | grep immich
The backups directory holds automatic database dumps; their retention is set
under Administration → Settings → Backup. The model cache in the
immich-model-cache volume can be deleted — it will be downloaded again.
Check that the jobs ran: Administration → Job Queues → Smart Search. The default CLIP model understands English queries only. Searching in another language requires a multilingual model, selected under Administration → Settings → Machine Learning → Smart Search; after changing the model, re-run the Smart Search job for the whole library.
Look at the migration logs:
docker compose logs --tail=200 immich-server | grep -i migration
Do not start the previous image against a migrated database — the only rollback is restoring the archive taken before the update. Skipped major versions also cause migration errors: upgrade one version at a time.
The database and the files came from different snapshots. Restore a consistent
pair from an archive created by backup.sh, and never mix database.sql.gz from
one archive with library.tar.gz from another.
restore.sh fails with a psql errorA dump must not be loaded into a database the server has already used. The script
removes the database volume before restoring; if you restore by hand, make sure
the database is empty and that immich-server has never started against it.
Fossary is an independent informational catalog and is not affiliated with the developers of the listed applications. We collect information from public sources and verify published recipes, but we do not develop, distribute, or control these applications.
A listing or validation status is not a requirement, endorsement, or personal recommendation to use an application. You decide whether it is suitable and use it at your own risk. We do not warrant an application's security, availability, or fitness for purpose and, to the extent permitted by law, are not liable for resulting loss or damage. Review its license, security settings, data processing, and backup procedures before installation.