Skip to content

Releases: heyvaldemar/immich-traefik-letsencrypt-docker-compose

v2.0.7

Choose a tag to compare

@heyvaldemar heyvaldemar released this 23 Sep 19:21

Fixed

  • CI had never run the restore scripts. The test restored with its own
    copy of the commands. The scripts read their database name, user, backup
    directory and data paths from the shell that ran them rather than from
    .env or the stack, so a value set in .env was not the one they used, they
    could only be run by hand, and a failed step left the stopped services
    stopped. They now take every value from the running backups container,
    accept the backup file name as an argument, start the services again
    whatever happens, and CI runs both.

Changed

  • The freshness check has its own workflow, Pin Freshness. It ran inside Deployment Verification, whose badge is the one at the top of this README. Across the fleet, nine red runs in ten were a pin one version behind - which the fleet's triage moves within the day - and a reader cannot tell that from a stack that does not boot. The badge now says whether the stack boots. The job itself is unchanged.

v2.0.6

Choose a tag to compare

@heyvaldemar heyvaldemar released this 21 Sep 18:29

Security

  • traefik:3.7 was rebuilt upstream; the pin moved from sha256:1c32e7c36820… to sha256:24841fe2de73…. Same version, same tag, a rebuilt base image — the usual shape of a security fix in a base layer.
  • valkey/valkey:9 was rebuilt upstream; the pin moved from sha256:c123e3715db6… to sha256:418652cfb58e…. Same version, same tag, a rebuilt base image — the usual shape of a security fix in a base layer.

Upgrading

git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.

Full history in CHANGELOG.md.

v2.0.5

Choose a tag to compare

@heyvaldemar heyvaldemar released this 18 Sep 14:53

Security

  • traefik:3.7 was rebuilt upstream; the pin moved from sha256:f86a2cab1b5c… to sha256:1c32e7c36820…. Same version, same tag, a rebuilt base image — the usual shape of a security fix in a base layer.

Upgrading

git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.

Full history in CHANGELOG.md.

v2.0.4

Choose a tag to compare

@heyvaldemar heyvaldemar released this 16 Sep 22:15

Changed

  • ghcr.io/immich-app/immich-server:v3.2.1 moved to ghcr.io/immich-app/immich-server:v3.2.2. The freshness check reported the lag; the deploy job booted the stack on the new image before this landed.
  • ghcr.io/immich-app/immich-machine-learning:v3.2.1 moved to ghcr.io/immich-app/immich-machine-learning:v3.2.2. The freshness check reported the lag; the deploy job booted the stack on the new image before this landed.

Upgrading

git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.

Full history in CHANGELOG.md.

v2.0.3

Choose a tag to compare

@heyvaldemar heyvaldemar released this 15 Sep 17:27

Changed

  • ghcr.io/immich-app/immich-server:v3.2.0 moved to ghcr.io/immich-app/immich-server:v3.2.1. The freshness check reported the lag; the deploy job booted the stack on the new image before this landed.
  • ghcr.io/immich-app/immich-machine-learning:v3.2.0 moved to ghcr.io/immich-app/immich-machine-learning:v3.2.1. The freshness check reported the lag; the deploy job booted the stack on the new image before this landed.

Upgrading

git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.

Full history in CHANGELOG.md.

v2.0.2

Choose a tag to compare

@heyvaldemar heyvaldemar released this 11 Sep 12:26

Changed

  • ghcr.io/immich-app/immich-server:v3.1.0 moved to ghcr.io/immich-app/immich-server:v3.2.0. The freshness check reported the lag; the deploy job booted the stack on the new image before this landed.
  • ghcr.io/immich-app/immich-machine-learning:v3.1.0 moved to ghcr.io/immich-app/immich-machine-learning:v3.2.0. The freshness check reported the lag; the deploy job booted the stack on the new image before this landed.

Upgrading

git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.

Full history in CHANGELOG.md.

What upstream changed

Read by fleet triage from the upstream release notes (or the commits between the tags) against this compose file, before the bump was applied.

Upstream changes v3.1.0 -> v3.2.0

Verdict: SAFE TO APPLY — the notes name no companion-service version requirement outside what the compose file already pins, and nothing in the release is flagged as breaking for a deployed host.

Breaking changes

  • none found in the notes. No section of the release is labeled breaking, and the "What's Changed" list is all features, enhancements, fixes, docs and translations.

Variables

  • none. No renamed, removed, or newly required environment variable is mentioned. The image-pin update needed is the routine version bump already covered by the repo's own convention: IMMICH_SERVER_IMAGE_VERSION and IMMICH_ML_IMAGE_VERSION in .env.example / the compose x-images block, which the compose file itself requires to move together: "The server and the machine-learning image are one release split across two containers: Immich supports no combination where they differ, so both version variables carry the same version and move together." This is not a new constraint introduced by this release, just something to remember when bumping the ML image pin.

Data and dependencies

  • none found. No new Postgres/Redis/Valkey version requirement is stated in these notes, so the compose file's existing pins (postgres:17-vectorchord0.4.3-pgvector0.8.0, valkey:9) are not contradicted.
  • One item to be aware of but not act on unattended: cluster groups (shared-user face clustering) is a new opt-in feature. Its notes say: "As of now, this requires resetting facial recognition for all users in the group, in order for the changes to apply retroactively for all assets. This means, names and birth dates will be lost..." This only fires if an admin/user actively creates or joins a cluster group and presses the re

Upstream changes v3.1.0 -> v3.2.0

Verdict: SAFE TO APPLY — the notes name no companion-service version requirement outside what the compose file already pins, and nothing in the release is flagged as breaking for a deployed host.

Breaking changes

  • none found in the notes. No section of the release is labeled breaking, and the "What's Changed" list is all features, enhancements, fixes, docs and translations.

Variables

  • none. No renamed, removed, or newly required environment variable is mentioned. The image-pin update needed is the routine version bump already covered by the repo's own convention: IMMICH_SERVER_IMAGE_VERSION and IMMICH_ML_IMAGE_VERSION in .env.example / the compose x-images block, which the compose file itself requires to move together: "The server and the machine-learning image are one release split across two containers: Immich supports no combination where they differ, so both version variables carry the same version and move together." This is not a new constraint introduced by this release, just something to remember when bumping the ML image pin.

Data and dependencies

  • none found. No new Postgres/Redis/Valkey version requirement is stated in these notes, so the compose file's existing pins (postgres:17-vectorchord0.4.3-pgvector0.8.0, valkey:9) are not contradicted.
  • One item to be aware of but not act on unattended: cluster groups (shared-user face clustering) is a new opt-in feature. Its notes say: "As of now, this requires resetting facial recognition for all users in the group, in order for the changes to apply retroactively for all assets. This means, names and birth dates will be lost..." This only fires if an admin/user actively creates or joins a cluster group and presses the re

v2.0.1

Choose a tag to compare

@heyvaldemar heyvaldemar released this 10 Sep 23:19

A correctness fix to the backup loop, and it is worth reading even if the symptom never reached you.

The archive is read back before it is called a backup

The library tarball was renamed into place on tar's exit code alone. That code has never been a statement about whether the file it produced opens, and the gap is not theoretical: an archive truncated after tar had already exited still carries exit status 0. The old condition promoted it, logged Data backup OK, and pruned older archives around it.

Measured in the image this sidecar actually runs, rather than argued from the manual:

case tar's exit code old condition with the read-back
a good archive 0 promoted promoted
destination blocked by a directory 2 refused refused
archive truncated after tar exited 0 promoted refused

One tar -tzf between the write and the rename now decides it.

What is deliberately not changed

The database dump. It is written as pg_dump \| gzip > f.partial under set -o pipefail, where a failure at either end of the pipe — including a full disk — already fails the pipeline and nothing is renamed. Adding gzip -t there would be noise, not safety.

How it was found

A rule was added to fleet-ops asserting this property across every repository, after one loop turned out to be missing it. Eighteen were, all with the same shape, all fixed in the same batch.

Upgrading

./update.sh

No variables changed, no data touched, no manual step.

v2.0.0

Choose a tag to compare

@heyvaldemar heyvaldemar released this 09 Sep 23:27

PostgreSQL 14 → 17. Immich's own compose file pins PostgreSQL 14, and PostgreSQL 14 goes out of support on 12 November 2026 — nine weeks from this release. Immich publishes the same VectorChord image on 15, 16 and 17, and its documentation supports anything from 14 up to 20, so the major is this template's choice within what Immich supports. 17 is supported until November 2029.

A fresh deployment gets it and needs nothing else.

If you are on v1.0.0

A PostgreSQL data directory belongs to one major version. Start 17 on a directory 14 wrote and the server exits with database files are incompatible with server, so restarting is not the upgrade path.

Run ./update.sh, which crosses to this tag and calls the migration for you, or run ./immich-upgrade-postgres.sh yourself after checking out v2.0.0. Either way, --dry-run first says what would happen without touching anything.

The migration dumps the database with the old server's own pg_dump, refuses to continue unless that dump reads back as a real archive, removes only the PostgreSQL data volume, starts 17 alone, loads the dump, and brings the rest of the stack up. VectorChord and pgvector cross in the dump as CREATE EXTENSION statements and the new image supplies them. The library volume is not touched.

Take your own copy of the dump it leaves behind: from the moment the old volume is removed, it is the only copy.

Proven, not asserted

The upgrade drill in CI ran this migration before the release was cut: v1.0.0 came up on PostgreSQL 14, a row was written to it, the migration dumped 18.3 MB, removed the old data directory, started 17 and loaded the dump, and the row read back from the new server. The ordinary HTTPS smoke test, the machine-learning check, the extension assertion and the eight backup and restore scenarios then all passed on the migrated stack.

Locally before that: Immich 3.1.0 healthy on PostgreSQL 17.6 with VectorChord 0.4.3 and pgvector 0.8.0, sixty-six tables, and no errors in the server log.

Full details in CHANGELOG.md.

v1.0.0

Choose a tag to compare

@heyvaldemar heyvaldemar released this 09 Sep 22:23

First release. A production deployment of Immich behind Traefik with automatic Let's Encrypt TLS, built to the fleet standard.

What it ships

Immich v3.1.0, with five images pinned to tag@sha256:<digest> as interpolation defaults in the compose file: the server, the machine-learning service, Immich's own PostgreSQL 14 build carrying VectorChord 0.4.3 and pgvector 0.8.1, Valkey 9, and Traefik 3.7. git pull alone delivers the tested combination.

Backups of both halves of the state. A photo library is a database that is the index and a directory of originals it points at; restore one without the other and you have rows pointing at nothing, or files nothing knows about. The backups container takes a pg_dump --clean --if-exists of the database and a tar.gz of the library on the same cycle, each written to a .partial name and renamed only on success. The library archive leaves out thumbs, encoded-video and Immich's own backups directory: the first two are rebuilt from the originals by a job in the web UI and together are usually larger than the originals, and the third holds dumps this loop already takes properly.

Two restore scripts, database and library, each of which validates the archive it was handed before it stops anything or deletes anything.

The database is not an ordinary PostgreSQL

Immich reads the VectorChord version at startup and refuses to run against one outside the range it supports. Three consequences this template handles:

  • The database pin travels with the Immich release, not with the PostgreSQL release calendar.
  • No command: overrides. Older instructions pass shared_preload_libraries and tuning arguments by hand; those settings live inside Immich's image now, selected between an SSD and an HDD profile by DB_STORAGE_TYPE.
  • CI asserts both extensions are present in the running database on every push, because a template that pins the wrong database image boots cleanly and fails the first time somebody searches.

Proven, not asserted

The deploy job requires, in order: the API answers {"res":"pong"} through Traefik, the machine-learning container answers the server over the internal network, vchord and vector are present in the running database, a database dump and a library archive are produced and readable, eight backup and restore scenarios pass, and Immich comes back up on the database the restore test replaced underneath it.

All of it ran before this was published, and again in CI on the first push.

Getting started

git clone https://github.com/heyvaldemar/immich-traefik-letsencrypt-docker-compose
cd immich-traefik-letsencrypt-docker-compose
docker network create traefik-network
docker network create immich-network
cp .env.example .env && $EDITOR .env
docker compose -f immich-traefik-letsencrypt-docker-compose.yml -p immich up -d

Five variables are required: IMMICH_DB_PASSWORD, IMMICH_HOSTNAME, TRAEFIK_HOSTNAME, TRAEFIK_ACME_EMAIL, TRAEFIK_BASIC_AUTH. Immich runs its migrations on first start and answers nothing until they finish. The first account registered becomes the administrator — open the site and register it before anyone else can.

Full details in README.md and CHANGELOG.md.