SSD Nodes Learn Hosting plans →
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-10-26

Immich auf einem VPS sichern und wiederherstellen

Erfahren Sie, was ein Immich-Backup braucht, warum ein Live-Postgres-Verzeichnis nicht genügt und welcher Restore-Fehler eine leere Zeitleiste erzeugt.

Was ein Immich-Backup enthalten muss

Ein Immich-Backup besteht aus drei Dingen, die zum selben Zeitpunkt erfasst wurden: den Originaldateien unter UPLOAD_LOCATION, einem SQL-Dump der Postgres-Datenbank sowie .env und docker-compose.yml, die den Stack beschreiben. Beim Wiederherstellen wird dieser Dump in eine neue Datenbank eingespielt, während der Immich-Server gestoppt ist. Erst danach wird der restliche Stack gestartet. Wenn die Reihenfolge nicht stimmt, läuft Immich zwar, zeigt aber eine leere Timeline auf einer vollständig belegten Festplatte.

Diese Aufteilung ist wichtig, weil Immich seinen Zustand an zwei Stellen speichert, die nichts voneinander wissen. Postgres enthält jedes Album, jeden Gesichtscluster, jeden freigegebenen Link, jedes Benutzerkonto und jeden API-Schlüssel sowie den gespeicherten Pfad jedes Assets. Das Dateisystem enthält die Bilddaten. Werden die Dateien ohne die Datenbank wiederhergestellt, zeigt Immich nichts an. Wird die Datenbank ohne die Dateien wiederhergestellt, lässt sich jedes Asset nur als defektes Bild öffnen.

Die folgenden Befehle beziehen sich auf Immich v3.1.0, die Anfang August 2026 aktuelle Version. Am 2026-10-25 ist v3.3.5 die aktuelle Version. Dabei handelt es sich um einen am 2026-10-21 veröffentlichten Security-Patch. Die Compose-Datei, das Datenbank-Image sowie die dokumentierten Schritte zum Sichern und Wiederherstellen entsprechen weiterhin den hier verwendeten Angaben. Das Projekt veröffentlicht schnell neue Versionen, und das dokumentierte Backup-Verfahren wurde bereits mehrmals geändert. Prüfen Sie deshalb die tatsächlich ausgeführte Version, bevor Sie etwas kopieren. Wenn der Stack noch nicht läuft, beginnen Sie mit der Immich-Installationsanleitung und kehren Sie anschließend hierher zurück.

Verstehen, worauf Ihre Pfade zeigen

Zwei Variablen in .env bestimmen alles auf dieser Seite. UPLOAD_LOCATION ist das übergeordnete Verzeichnis, in das Immich alle Mediendateien schreibt. DB_DATA_LOCATION ist das Datenverzeichnis von Postgres.

Das standardmäßige example.env setzt UPLOAD_LOCATION=./library. Das ist ein verwirrender Standardwert, weil Immich darin anschließend einen Ordner namens library erstellt. Ihre Originale landen unter ./library/library. Verwenden Sie stattdessen einen absoluten Pfad. Dann hängt ein Backup-Skript nie davon ab, aus welchem Verzeichnis Sie es ausführen.

UPLOAD_LOCATION=/srv/immich/data
DB_DATA_LOCATION=/srv/immich/postgres
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
IMMICH_VERSION=v3.1.0

In UPLOAD_LOCATION erstellt Immich mehrere Ordner. Drei davon enthalten Daten, die kein Auftrag wiederherstellen kann:

  • library: die Originale, entsprechend Ihrer Speichervorlage angeordnet
  • upload: Originale, die noch nicht in die Struktur der Vorlage verschoben wurden, sowie laufende Uploads
  • profile: Benutzerprofilbilder

Wenn library verloren geht, ist das Foto verloren. Immich speichert von einem Original nirgendwo eine zweite Kopie.

Warum das Kopieren des Postgres-Datenverzeichnisses kein Backup ist

DB_DATA_LOCATION wirkt wie ein einfaches Ziel. Es ist ein Verzeichnis, rsync kann es kopieren, und der Kopiervorgang endet ohne Fehler. Wenn Sie es kopieren, während Postgres läuft, ist die Kopie kein Backup. Wenn Sie es bei gestopptem Postgres kopieren, ist sie zwar ein Backup, aber ein anfälliges. Dafür gibt es zwei Gründe, die sich beide beobachten lassen.

Der erste Grund ist ein inkonsistenter Kopierstand. Postgres schreibt jede Änderung zunächst in das Write-Ahead Log (WAL) und übernimmt sie erst bei einem Checkpoint in die Tabellendateien. Zu jedem Zeitpunkt befinden sich die Dateien auf dem Datenträger daher in einem Zwischenzustand. Eine laufende Kopie, die vier Minuten dauert, liest die erste Datei um 02:00 und die letzte um 02:04. Diese beiden Dateien gehören nicht zur selben Transaktion. Wenn Sie Postgres mit dem Ergebnis starten, verweigert es entweder den Start mit PANIC: could not locate a valid checkpoint record, oder es startet und beendet sich beim ersten Lesen einer beschädigten Seite mit invalid page in block 1234 of relation base/16384/.... Aus dieser Kopie lässt sich keiner der beiden Zustände wiederherstellen.

Der zweite Grund betrifft eine Kopie, die Sie bei vollständig gestoppten Diensten erstellen. PostgreSQL dokumentiert eine vollständige Kopie eines heruntergefahrenen Datenverzeichnisses als gültiges Backup. Dieses Verzeichnis kann jedoch nur von Binärdateien geöffnet werden, die dasselbe Speicherformat verwenden. Immich pinnt sein Datenbank-Image derzeit mit dem Digest ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0. Darin enthalten ist Postgres 14 mit den integrierten Vektor-Such-Erweiterungen VectorChord, pgvector und pgvecto.rs. Immich selbst verwendet inzwischen VectorChord. pgvecto.rs ist in diesem Image nur noch enthalten, damit ältere Installationen davon migrieren können und alte Backups weiterhin wiederhergestellt werden können. Eine spätere Minor-Version von Postgres 14 kann das Verzeichnis unverändert öffnen, eine andere Postgres-Major-Version jedoch nicht. Auch die von Ihren Tabellen benötigten Erweiterungen müssen in kompatiblen Versionen vorhanden sein. Der Host für die Wiederherstellung muss ein kompatibles Image ausführen. Ein SQL-Dump ist davon unabhängig: Er besteht aus Text, und jeder kompatible Server kann ihn einspielen.

pg_dump umgeht das Problem inkonsistenter Kopien vollständig. Es liest die gesamte Datenbank innerhalb eines einzigen MVCC-Snapshots (Multi-Version Concurrency Control). Dadurch sieht es die Datenbank genau so, wie sie zu einem bestimmten Zeitpunkt war, während andere Schreibvorgänge parallel weiterlaufen. Deshalb müssen Sie Postgres für einen Dump nicht stoppen.

Was Sie aus dem Backup weglassen können

Diese Daten werden automatisch neu erzeugt und können daher weggelassen werden:

  • thumbs: Vorschau- und Miniaturbilder
  • encoded-video: transkodierte Videos
  • DB_DATA_LOCATION: aus dem Dump neu erstellt
  • das Docker-Volume model-cache: Machine-Learning-Modelle, die bei Bedarf erneut heruntergeladen werden

Das Weglassen ist eine Abwägung und kein kostenloser Vorteil. Das erneute Erzeugen von Miniaturbildern und Transkodierungen für eine große Bibliothek benötigt auf einem kleinen VPS mehrere Stunden CPU-Zeit. Währenddessen zeigt die Zeitleiste durchgehend graue Platzhalter. Sie starten die Verarbeitung unter Administration > Jobs erneut, indem Sie "Generate Thumbnails" und "Transcode Videos" so konfigurieren, dass fehlende Assets verarbeitet werden. Wenn das Backup-Ziel ausreichend Speicherplatz hat, nehmen Sie diese Daten auf und vermeiden Sie die Wartezeit. Wenn der Speicherplatz knapp ist, lassen Sie sie weg und planen Sie die Neuerstellung ein. Die Größe einer Immich-Bibliothek beschreibt, wie stark diese Verzeichnisse im Verhältnis zu den Originaldateien wachsen.

Ein weiteres Verzeichnis sollten Sie kennen. UPLOAD_LOCATION/backups enthält die automatischen Datenbank-Dumps von Immich. Sie werden täglich um 02:00 erstellt, wobei die letzten 14 Dumps aufbewahrt werden. Die Einstellung finden Sie unter Administration > Settings > Database Dump Settings. Diese Dumps verursachen keinen zusätzlichen Aufwand und sind tatsächlich nützlich. Sie liegen jedoch auf demselben Datenträger wie die Bibliothek, die sie schützen. Sie helfen daher bei einer fehlerhaften Migration, nicht aber bei einem ausgefallenen Server. Erstellen Sie trotzdem einen eigenen Dump, weil dieser zum selben Zeitpunkt wie der zugehörige Snapshot der Dateien erstellt werden kann.

Datenbank-Dump erstellen

docker exec -t immich_postgres pg_dump --clean --if-exists \
  --dbname=immich --username=postgres \
  | gzip > /srv/immich/backup/immich.sql.gz

Ersetzen Sie immich und postgres durch Ihre Werte für DB_DATABASE_NAME und DB_USERNAME, falls Sie diese geändert haben. --clean --if-exists setzt vor jedes CREATE ein DROP ... IF EXISTS. Dadurch wird der Dump in eine Datenbank eingespielt, die bereits Objekte enthält, statt beim ersten vorhandenen Objekt abzubrechen.

Nun zu dem Detail, das Backup-Skripte unbemerkt unzuverlässig macht. Der Befehl verwendet eine Pipeline. Eine Shell meldet den Exit-Status des letzten Befehls in einer Pipeline. Wenn pg_dump wegen eines falschen Passworts oder eines nicht laufenden Containers fehlschlägt, erhält gzip einen leeren Datenstrom, schreibt eine formal gültige gzip-Datei und beendet sich mit dem Status 0. Ihr Skript protokolliert Erfolg, und Sie haben ein 20 Byte großes Backup. Setzen Sie pipefail an den Anfang jedes Backup-Skripts:

#!/usr/bin/env bash
set -euo pipefail

Prüfen Sie anschließend das Ergebnis, statt dem Exit-Code zu vertrauen:

ls -lh /srv/immich/backup/immich.sql.gz
gunzip -c /srv/immich/backup/immich.sql.gz | head -n 3

Die erste Zeile eines gültigen Dumps lautet -- PostgreSQL database dump. Eine Datei mit wenigen hundert Bytes ist ein fehlgeschlagener Dump, unabhängig davon, was das Skript meldet.

Ermitteln Sie neben dem Dump, welcher Release ihn erstellt hat. Fragen Sie dazu den laufenden Server ab:

curl -fsS http://localhost:2283/api/server/version > /srv/immich/backup/immich-version.txt

Dieser Endpunkt benötigt keine Anmeldung und gibt den laufenden Release als Major-, Minor- und Patch-Nummer zurück. Daher stehen 3, 1 und 0 für v3.1.0. Verlassen Sie sich dafür nicht auf .env und auch nicht auf docker inspect --format '{{.Config.Image}}' immich_server. docker inspect --format '{{.Config.Image}}' immich_server gibt lediglich die von Ihnen konfigurierte Image-Referenz aus. Die Standarddatei setzt IMMICH_VERSION=v3, ein veränderliches Tag, das jedem 3.x-Release folgt. Ein Eintrag mit :v3 sagt daher nichts darüber aus, welcher Build den Dump tatsächlich erstellt hat. Legen Sie in .env ebenfalls das exakte Tag fest.

Server anhalten und anschließend mit restic einen Snapshot erstellen

Dateien unter UPLOAD_LOCATION sind nicht unveränderlich, während Immich läuft. Der Server schreibt neue Uploads, und der Speicher-Template-Job verschiebt Dateien zwischen Verzeichnissen. Wenn ein Backup-Tool eine Datei liest, während sie teilweise geschrieben wird, speichert es diese Bytes so, als wären sie die vollständige Datei. Dabei wird kein Fehler gemeldet. Halten Sie den Server-Container für die Dauer des Vorgangs an:

docker stop immich_server

Lassen Sie immich_postgres weiterlaufen, weil der Dump diesen Dienst benötigt. Die Weboberfläche und die mobile App sind offline, bis Sie den Server wieder starten. Bei einer privaten Instanz um 03:00 ist das normalerweise unproblematisch.

restic passt hier, weil es Daten dedupliziert und verschlüsselt, bevor sie den Server verlassen. Verweisen Sie auf ein Repository, das nicht auf diesem Server liegt:

export RESTIC_REPOSITORY=sftp:backup@backup.example.com:/srv/restic/immich
export RESTIC_PASSWORD_FILE=/root/.restic-password
restic init

Object Storage funktioniert auf dieselbe Weise. Es ist die bessere Lösung, wenn die Kopie vollständig außerhalb Ihrer eigenen Hardware liegen soll:

export RESTIC_REPOSITORY=s3:https://s3.example.com/immich-backup
export AWS_ACCESS_KEY_ID=your-access-key
export AWS_SECRET_ACCESS_KEY=your-secret-key
restic init

Dieser Endpunkt kann auf einen MinIO-Bucket, den Sie selbst betreiben auf einem zweiten Rechner oder auf einen beliebigen S3-kompatiblen Anbieter verweisen. Ein Repository auf derselben Festplatte wie die Bibliothek schützt Sie vor einem versehentlichen Löschen, aber vor keinem anderen Ausfall.

Erstellen Sie anschließend den Snapshot, der genau die relevanten Dateien erfasst:

restic backup \
  /srv/immich/backup/immich.sql.gz \
  /srv/immich/backup/immich-version.txt \
  /srv/immich/data/library \
  /srv/immich/data/upload \
  /srv/immich/data/profile \
  /srv/immich/.env \
  /srv/immich/docker-compose.yml
docker start immich_server

restic liest bei jedem Lauf den gesamten Verzeichnisbaum, lädt aber nur Blöcke hoch, die es noch nicht kennt. Der erste Snapshot überträgt daher Ihre gesamte Bibliothek. Jeder weitere Snapshot überträgt nur die an diesem Tag neu hinzugekommenen Fotos.

Aufbewahrung und Schlüssel, die an einem anderen Ort liegen müssen

restic forget --prune --keep-daily 7 --keep-weekly 5 --keep-monthly 12

forget entfernt Snapshots aus dem Index. --prune ist der Teil, der die Daten löscht, auf die diese Snapshots zuletzt verwiesen haben. Wenn Sie forget ohne --prune ausführen, sinken Ihre Speicherkosten nie.

Strukturprüfungen sind kostengünstig. Führen Sie daher einmal pro Woche eine aus:

restic check

Damit wird geprüft, ob die Repository-Metadaten konsistent sind. Ihre Daten werden dabei nicht gelesen. Lesen Sie einmal pro Monat ein Beispiel erneut ein und prüfen Sie es gegen die aufgezeichneten Hashes:

restic check --read-data-subset=5%

Nur diese Prüfung erkennt stille Beschädigungen im Storage-Backend, weil dabei echte Blöcke heruntergeladen und ihre Prüfsummen neu berechnet werden. Ein vollständiges --read-data einer Fotosammlung bedeutet, das gesamte Repository herunterzuladen. Bei Object Storage mit nutzungsabhängiger Abrechnung kostet das tatsächlich Geld. Deshalb wird in der Praxis ein fortlaufend wechselnder Teilbestand verwendet.

Nun zum Punkt, den viele überspringen. Ein Passwort für ein restic-Repository kann nicht wiederhergestellt werden. Es gibt weder eine Zurücksetzung noch ein Support-Ticket. Wenn die einzige Kopie in /root/.restic-password auf dem Server liegt, den Sie gerade wiederherstellen möchten, sind Ihre Backups nur verschlüsseltes Rauschen. Dasselbe gilt für den Zugriffsschlüssel des Object Storage und für DB_PASSWORD aus .env. Bewahren Sie alle diese Informationen an einem Ort auf, der nicht davon abhängt, dass dieser Rechner läuft: ausgedruckt in einer Schublade oder in einem Passwortmanager auf anderer Hardware. Wenn auch dieser Manager selbst gehostet wird, gelten dafür dieselben Anforderungen. Vaultwarden zu sichern ist eine eigene Aufgabe.

Immich in der richtigen Reihenfolge wiederherstellen

Bei der Wiederherstellung entscheidet die Reihenfolge darüber, ob ein gutes Backup zu einer leeren Zeitleiste führt. Befolgen Sie auf dem neuen Host diese Abfolge.

Stellen Sie zuerst die Konfiguration wieder her. Sie legt fest, welche Version ausgeführt wird und auf welche Pfade verwiesen wird.

restic restore latest --target /restore \
  --include /srv/immich/.env \
  --include /srv/immich/docker-compose.yml \
  --include /srv/immich/backup

Fixieren Sie die Version, bevor etwas startet. Lesen Sie immich-version.txt. Setzen Sie IMMICH_VERSION in .env auf genau diese Version (v3.1.0 für Major 3, Minor 1, Patch 0). Lassen Sie die neueste Version zunächst unberücksichtigt. Immich unterstützt kein Downgrade, auch nicht zwischen Patch-Versionen. Wenn ein neuerer Server mit einem älteren Dump startet und seine Migrationen ausführt, gibt es keinen Weg zurück.

Stellen Sie die Mediendateien wieder her.

restic restore latest --target /restore --include /srv/immich/data

Verschieben Sie anschließend library, upload und profile so, dass sie direkt innerhalb des Pfads liegen, auf den UPLOAD_LOCATION auf diesem Host verweist. Der Hostpfad selbst darf sich ändern, weil die Compose-Datei dieses Verzeichnis an einen festen Pfad im Container bindet. Die darin enthaltene Verzeichnisstruktur darf sich nicht ändern.

Starten Sie die Datenbank allein. Lassen Sie DB_DATA_LOCATION leer, damit Postgres einen frischen Cluster initialisiert.

cd /srv/immich
docker compose pull
docker compose create
docker start immich_postgres
docker exec immich_postgres pg_isready --username=postgres

pg_isready gibt accepting connections aus, sobald die Ersteinrichtung abgeschlossen ist. Das dauert einige Sekunden. docker compose create erstellt alle Container, ohne sie zu starten. Genau darum geht es bei diesem Schritt: Der Immich-Server darf noch nicht laufen. Ein Server, der mit einer leeren Datenbank startet, führt seine Migrationen aus, erstellt ein neues Schema und fordert Sie auf, ein neues Administratorkonto anzulegen. Danach würden Sie einen Dump unterhalb einer laufenden Anwendung einspielen.

Spielen Sie den Dump ein.

gunzip --stdout /restore/srv/immich/backup/immich.sql.gz \
  | sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" \
  | docker exec -i immich_postgres psql --dbname=immich --username=postgres \
      --single-transaction --set ON_ERROR_STOP=on

Zwei Bestandteile dieses Befehls übernehmen dabei die eigentliche Arbeit. sed ist erforderlich, weil pg_dump vorsorglich ein leeres search_path in die Ausgabe schreibt. Dadurch können nicht qualifizierte Namen im Dump nicht versehentlich auf ein unerwartetes Schema verweisen. Die Vektorsuchtypen von Immich befinden sich in public. Bei einem leeren Suchpfad erreicht die Wiederherstellung daher die erste Spalte mit einem Vektortyp, und psql bricht mit ERROR: type "vector" does not exist ab. Wenn Sie public wieder in den Suchpfad aufnehmen, wird das Problem behoben.

--single-transaction --set ON_ERROR_STOP=on führt die gesamte Wiederherstellung in einer Transaktion aus und bricht beim ersten Fehler ab. Sie erhalten entweder eine vollständige Datenbank oder eine unveränderte Datenbank. Ohne diese Option hinterlässt ein Fehler in der Mitte eine Datenbank, die startet und Ihre Anmeldung akzeptiert, der aber eine unbekannte Anzahl von Alben fehlt. Das bemerken Sie möglicherweise erst Wochen später.

Starten Sie jetzt alles.

docker compose up -d
docker compose ps
docker logs -f immich_server

Warten Sie auf eine Startmeldung wie Immich Server is listening on. Öffnen Sie anschließend Port 2283 und melden Sie sich mit Ihren bisherigen Zugangsdaten an, da die Benutzerkonten mit dem Dump wiederhergestellt wurden. Wenn die Anmeldeseite stattdessen das Erstellen des ersten Administratorkontos anbietet, wurde die Datenbank nicht wiederhergestellt. Stoppen Sie den Vorgang und prüfen Sie die psql-Ausgabe erneut.

Beachten Sie einen wichtigen Punkt bei den offiziellen Befehlen zur Wiederherstellung über die Kommandozeile, die mit docker compose down -v beginnen. -v entfernt benannte Volumes. In der standardmäßigen Compose-Datei sind UPLOAD_LOCATION und DB_DATA_LOCATION Bind-Mounts und bleiben daher erhalten. Wenn Sie einen dieser Pfade in ein benanntes Volume geändert haben, löscht dieser Befehl Ihre Fotos. Lesen Sie die Compose-Datei, bevor Sie den Befehl ausführen.

Warum die Zeitleiste nach einer Wiederherstellung leer ist

Die Zeitleiste wird aus Datenbankzeilen erzeugt. Immich durchsucht upload/ beim Start nie, um Fotos erneut zu erkennen, weil eine Datei ohne Datenbankzeile keinen Besitzer, kein Datum und kein Album hat. Die häufigste fehlerhafte Wiederherstellung besteht daher darin, dass die Dateien vorhanden sind, die Datenbank aber fehlt. Immich startet, legt ein leeres Schema an und stellt Ihnen eine funktionierende Instanz bereit, die keine Inhalte enthält, während die Festplatte mit Ihren Fotos gefüllt ist. Es ist nichts verloren. Sichtbar ist jedoch ebenfalls nichts. Die Lösung besteht darin, den Dump bei gestopptem Server genau wie oben erneut einzuspielen.

Die zweite Variante ist unauffälliger. Die Datenbank wird wiederhergestellt, die Zeitleiste füllt sich mit Einträgen, und jedes Asset kann nicht geöffnet werden. Das bedeutet, dass die Zeilen auf Dateien verweisen, die der Container nicht sehen kann. Ursache ist meist, dass library, upload und profile nach einem restic restore --target /restore eine Ebene zu tief liegen, weil niemand es an die richtige Stelle verschoben hat. Prüfen Sie dies innerhalb des Containers, statt zu raten:

docker exec immich_server ls /data

Die mitgelieferte Compose-Datei bind-mountet UPLOAD_LOCATION nach /data. Die Auflistung sollte daher library, upload und profile anzeigen. Wenn ein leeres Verzeichnis oder ein fremder Ordner srv angezeigt wird, verweist Ihr Bind-Mount auf die falsche Ebene. Die Zeilen sind dann korrekt.

Versionsübereinstimmung zwischen Backup und Wiederherstellung

Immich veröffentlicht häufig neue Versionen, und das Schema wird dabei angepasst. Ein Dump enthält daher das Schema des Servers, von dem er erstellt wurde.

Das Wiederherstellen eines älteren Dumps auf einem neueren Server funktioniert in der Regel, weil der Server beim Start ausstehende Migrationen ausführt und das Schema weiterentwickelt. In der eigenen Backup-Dokumentation empfiehlt Immich dennoch, den Dump nach Möglichkeit in einer kompatiblen Version wiederherzustellen. Bei nicht übereinstimmenden Versionen werden während der Wiederherstellung Migrationen ausgeführt. Das Projekt beschränkt inkompatible Änderungen auf Major-Releases und dokumentiert sie in den Release Notes. Eine Wiederherstellung über eine Major-Version hinweg sollten Sie daher zuerst genau prüfen.

Das Wiederherstellen eines neueren Dumps auf einem älteren Server funktioniert überhaupt nicht. Der Dump enthält Tabellen und Spalten, die der ältere Code nicht kennt. Immich weist außerdem darauf hin, dass ein Downgrade selbst zwischen Patch-Releases nicht unterstützt wird. Es gibt keinen Rollback-Befehl, den Sie dafür verwenden können.

Die sichere Wiederherstellung ist daher unspektakulär. Führen Sie exakt die Version aus, mit der der Dump erstellt wurde, spielen Sie ihn ein, melden Sie sich an, prüfen Sie, ob die Timeline vollständig ist, und aktualisieren Sie erst danach. Führen Sie das Upgrade so durch, wie es auf der offiziellen Upgrade-Seite beschrieben ist: Lesen Sie die Release Notes zu inkompatiblen Änderungen, setzen Sie IMMICH_VERSION in .env auf die gewünschte Version und führen Sie anschließend docker compose pull && docker compose up -d aus. Wenn Sie eine Woche lang Dumps aufbewahren, hilft das ebenfalls: Falls der neueste Dump während eines fehlgeschlagenen Upgrades erstellt wurde, befindet sich der Dump vom Vortag weiterhin im Repository.

Backup jeden Monat überprüfen

Ein Backup, das Sie noch nie wiederhergestellt haben, ist nur eine Vermutung. Stellen Sie es einmal im Monat in einer Wegwerf-Instanz wieder her und sehen Sie sich ein Foto an. Die Prüfung dauert etwa zwanzig Minuten. Nur dadurch wird der Rest dieser Seite zu einem Wiederherstellungsplan.

restic snapshots
restic stats latest

snapshots sollte den Lauf der vergangenen Nacht auflisten. stats latest sollte eine Größe nahe der Größe Ihrer Bibliothek ausgeben, nicht nur wenige Megabytes.

Stellen Sie das Backup in einem temporären Verzeichnis wieder her, idealerweise auf einem Ersatzhost:

restic restore latest --target /tmp/immich-drill

Kopieren Sie docker-compose.yml und .env aus dem wiederhergestellten Bestand heraus. Ändern Sie anschließend drei Dinge in der Kopie. Verweisen Sie mit UPLOAD_LOCATION und DB_DATA_LOCATION auf Verzeichnisse unter /tmp/immich-drill. Veröffentlichen Sie den Webport an einer anderen Stelle, also 12283:2283 statt 2283:2283. Löschen Sie die Zeilen container_name:, weil die mitgelieferte Compose-Datei Namen wie immich_server fest vorgibt. Dadurch kollidiert ein zweiter Stack auf demselben Host mit dem ersten, und Docker verweigert dessen Erstellung.

Führen Sie die oben beschriebene Wiederherstellungssequenz aus: nur die Datenbank, den Dump einspielen und anschließend docker compose up -d. Führen Sie nun die vier Prüfungen durch, die den Erfolg belegen.

  1. Melden Sie sich mit dem Passwort an, das Sie vor der Prüfung verwendet haben. Funktionierende Konten zeigen, dass der Dump wiederhergestellt wurde.
  2. Öffnen Sie die Zeitleiste und blättern Sie zum ältesten Monat. Assets über den gesamten Datumsbereich zeigen, dass alle Datensätze zurückgekommen sind, nicht nur die aktuellen.
  3. Öffnen Sie ein Foto in voller Größe und laden Sie das Original herunter.
  4. Vergleichen Sie es mit derselben Datei in Ihrer aktiven Bibliothek mit sha256sum. Übereinstimmende Hashes zeigen, dass die Bytes den vollständigen Weg durch restic überstanden haben.

Räumen Sie die Prüfung anschließend mit docker compose down -v im Prüfverzeichnis auf und löschen Sie /tmp/immich-drill. Notieren Sie das Datum an einer Stelle, an der Sie es sehen, denn der Nutzen dieser Prüfung liegt vollständig darin, sie im nächsten Monat erneut durchzuführen. Wenn Sie noch entscheiden, für welchen Fotoserver Sie sich festlegen möchten, beschreibt der Vergleich von PhotoPrism und Immich, worin sich beide genau in diesem Punkt unterscheiden.

FAQ

Muss ich Immich für die Sicherung stoppen?

Stoppen Sie immich_server und lassen Sie immich_postgres weiterlaufen. Die Datenbank muss nicht pausiert werden, weil pg_dump innerhalb eines einzelnen MVCC-Snapshots liest und unabhängig von anderen Schreibvorgängen einen konsistenten Zeitpunkt sieht. Der Grund für das Stoppen sind die Dateien: Der Server schreibt neue Uploads, und der Storage-Template-Job verschiebt Dateien zwischen Verzeichnissen. Ein Backup-Tool kann daher eine Datei während eines Schreibvorgangs lesen und ohne Fehlermeldung eine abgeschnittene Kopie speichern. docker stop immich_server vor dem Snapshot und docker start immich_server danach beseitigt dieses Race.

Kann ich das Postgres-Datenverzeichnis kopieren, statt pg_dump auszuführen?

Nicht, solange Postgres läuft. Eine fortlaufende Kopie eines aktiven Datenverzeichnisses liest verschiedene Dateien zu unterschiedlichen Zeitpunkten. Das Ergebnis entspricht daher keinem konsistenten Zustand. Postgres weist die Kopie beim Start mit PANIC: could not locate a valid checkpoint record zurück oder scheitert später an einer beschädigten Seite. Eine vollständige Kopie, die bei gestopptem Postgres erstellt wurde, ist eine gültige Sicherung. Sie kann jedoch nur unter derselben Postgres-Hauptversion mit kompatiblen Erweiterungen geöffnet werden. Immich verwendet ein Postgres-14-Image mit VectorChord, pgvector und pgvecto.rs. Das Verzeichnis lässt sich nicht unter einer anderen Hauptversion öffnen. Ein SQL-Dump besteht aus Klartext und kann in jeden kompatiblen Server eingespielt werden. Er bleibt daher die aufzubewahrende Kopie.

Warum ist meine Immich-Zeitleiste nach einer Wiederherstellung leer?

Weil die Zeitleiste aus Datenbankzeilen erstellt wird und Sie die Dateien ohne die Datenbank wiederhergestellt haben. Immich durchsucht upload/ niemals erneut, um Fotos zu erkennen. Dateien ohne zugehörige Zeilen bleiben daher unsichtbar. Die Fotos selbst sind unverändert. Stoppen Sie den Server, spielen Sie den Dump in eine frisch initialisierte Postgres-Datenbank ein und starten Sie anschließend den Stack. Wenn die Zeitleiste dagegen vollständig ist, aber jedes Foto nicht geöffnet werden kann, liegt das umgekehrte Problem vor: library, upload und profile befinden sich nicht direkt innerhalb des in den Container eingebundenen Verzeichnisses. Prüfen Sie dies mit docker exec immich_server ls /data.

Welche Immich-Verzeichnisse kann ich bei einer Sicherung auslassen?

thumbs und encoded-video werden aus den Originalen neu erzeugt, und DB_DATA_LOCATION wird aus dem Dump wiederhergestellt. Daher muss keines dieser Verzeichnisse im Backup enthalten sein. Wenn Sie sie auslassen, benötigen Sie nach einer Wiederherstellung mehr Zeit statt vorher mehr Speicherplatz. Das Neuerstellen von Vorschauen und Transcodierungen für eine große Bibliothek benötigt mehrere Stunden CPU-Zeit. Starten Sie den Vorgang unter Administration > Jobs für fehlende Assets. Niemals auslassen dürfen Sie library, upload und profile. Diese Verzeichnisse enthalten die einzige Kopie jedes Originals.

Kann ich einen Immich-Dump in eine neuere Version einspielen?

In der Regel ja, weil der Server beim Start ausstehende Migrationen ausführt und das Schema schrittweise aktualisiert. Der umgekehrte Vorgang schlägt fehl: Immich unterstützt kein Downgrade, auch nicht zwischen Patch-Releases. Ein Dump aus einer neueren Version kann daher nicht in einen älteren Server geladen werden. Stellen Sie mit IMMICH_VERSION, das auf das Release festgelegt ist, das den Dump erstellt hat, wieder her. Prüfen Sie, ob die Zeitleiste vollständig ist, und führen Sie erst danach das Upgrade durch. Erfassen Sie das Release neben jedem Dump mit curl -fsS http://localhost:2283/api/server/version. docker inspect gibt nur den konfigurierten Image-Verweis aus, und IMMICH_VERSION=v3 ist standardmäßig ein veränderlicher Tag, der keine verlässliche Information liefert.

War dieser Artikel hilfreich?