Jak wykonać kopię zapasową i przywrócić Immich na VPS
Dowiedz się, jak poprawnie zabezpieczyć Immich. Wyjaśniamy, dlaczego kopiowanie folderu Postgres to błąd i jak uniknąć pustej osi czasu podczas przywracania danych w wersji v3.1.0.
Co musi zawierać kopia zapasowa Immich
Kopia zapasowa Immich składa się z trzech elementów zabezpieczonych w tym samym momencie. Są to pliki źródłowe w UPLOAD_LOCATION, zrzut SQL bazy danych Postgres oraz pliki .env i docker-compose.yml, które opisują stos. Przywracanie polega na wgraniu zrzutu do czystej bazy danych przy zatrzymanym serwerze Immich i uruchomieniu reszty stosu dopiero po zakończeniu tej operacji. Błędna kolejność działań spowoduje, że Immich będzie działać, ale wyświetli pustą oś czasu mimo pełnego dysku.
Ten podział jest istotny, ponieważ Immich przechowuje swój stan w dwóch niezależnych od siebie miejscach. Postgres przechowuje informacje o każdym albumie, klastrze twarzy, udostępnionym linku, koncie użytkownika, kluczu API oraz ścieżce do każdego zasobu. System plików przechowuje dane obrazów. Przywrócenie plików bez bazy danych sprawi, że Immich nie wyświetli żadnych treści. Przywrócenie bazy danych bez plików spowoduje, że każdy zasób będzie wyświetlał uszkodzony obraz.
Polecenia w tym dokumencie zostały przygotowane dla Immich w wersji v3.1.0, która była aktualna na początku sierpnia 2026 roku. Projekt rozwija się szybko, a udokumentowana procedura tworzenia kopii zapasowych zmieniała się już kilkukrotnie, dlatego przed skopiowaniem jakichkolwiek poleceń należy sprawdzić wersję, która jest aktualnie używana. Jeśli stos nie został jeszcze uruchomiony, należy zacząć od przewodnika instalacji Immich, a następnie wrócić do tego miejsca.
Zrozumienie wskazań ścieżek
Dwie zmienne w .env decydują o wszystkim na tej stronie. UPLOAD_LOCATION to katalog nadrzędny, w którym Immich zapisuje wszystkie multimedia. DB_DATA_LOCATION to katalog danych Postgres.
Domyślna konfiguracja example.env ustawia UPLOAD_LOCATION=./library, co jest mylącym ustawieniem domyślnym, ponieważ Immich tworzy wewnątrz niego folder o nazwie library. Oryginalne pliki trafiają do ./library/library. Należy ustawić ścieżkę bezwzględną, aby skrypt kopii zapasowej nigdy nie zależał od katalogu, z którego został uruchomiony.
UPLOAD_LOCATION=/srv/immich/data
DB_DATA_LOCATION=/srv/immich/postgres
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
IMMICH_VERSION=v3.1.0Wewnątrz UPLOAD_LOCATION Immich tworzy kilka folderów. Trzy z nich przechowują dane, których żadne zadanie nie jest w stanie odtworzyć:
library: oryginalne pliki, rozmieszczone zgodnie z szablonem przechowywaniaupload: oryginalne pliki jeszcze nieprzeniesione do układu szablonu oraz przesyłane daneprofile: zdjęcia profilowe użytkowników
Utrata library oznacza bezpowrotną utratę zdjęcia. Immich nie przechowuje nigdzie drugiej kopii oryginału.
Dlaczego kopiowanie katalogu danych Postgres nie jest kopią zapasową
DB_DATA_LOCATION wygląda na łatwy cel. Jest to katalog, rsync go skopiuje, a operacja zakończy się bez błędu. Mimo to nie jest to kopia zapasowa z dwóch powodów, których skutki można zaobserwować.
Pierwszym jest niespójność danych (tearing). Postgres zapisuje każdą zmianę najpierw w dzienniku transakcyjnym (WAL), a dopiero później nanosi ją na pliki tabel podczas punktu kontrolnego (checkpoint). W każdej chwili pliki na dysku są w trakcie modyfikacji, a kopiowanie trwające cztery minuty odczytuje pierwszy plik o 02:00, a ostatni o 02:04. Te dwa pliki nie należą do tej samej transakcji. Po uruchomieniu Postgresa na takiej kopii, serwer albo odmawia startu z błędem PANIC: could not locate a valid checkpoint record, albo uruchamia się i ulega awarii przy pierwszej próbie odczytu uszkodzonej strony z błędem invalid page in block 1234 of relation base/16384/.... Żaden z tych przypadków nie pozwala na odzyskanie danych z takiej kopii.
Drugi powód występuje nawet wtedy, gdy najpierw zatrzymasz wszystkie procesy. Katalog danych Postgres jest powiązany z konkretnymi plikami binarnymi, które go utworzyły. Immich przypisuje obraz bazy danych za pomocą skrótu (digest), obecnie ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0. Jest to Postgres 14 z dwoma skompilowanymi rozszerzeniami do wyszukiwania wektorowego. Katalog danych zapisany przez tę kompilację nie otworzy się w innej głównej wersji Postgresa ani w kompilacji z innymi wersjami rozszerzeń. Host przywracający dane musi dokładnie odtworzyć środowisko. Zrzut SQL (SQL dump) nie ma tego problemu: jest to tekst, który każdy kompatybilny serwer może przetworzyć.
pg_dump całkowicie eliminuje problem niespójności danych. Odczytuje całą bazę danych w ramach pojedynczej migawki MVCC (multi-version concurrency control), dzięki czemu widzi bazę dokładnie w takim stanie, w jakim znajdowała się w jednej chwili, podczas gdy inne operacje zapisu są kontynuowane. Dlatego nie trzeba zatrzymywać Postgresa, aby wykonać zrzut.
Co można pominąć w kopii zapasowej
Elementy te generują się automatycznie, więc można je pominąć:
thumbs: podglądy i miniatury obrazówencoded-video: transkodowane wideoDB_DATA_LOCATION: pliki odtwarzane z zrzutu bazy danych- wolumen Docker
model-cache: modele uczenia maszynowego, pobierane ponownie na żądanie
Pominięcie tych danych to kompromis, a nie darmowy zysk. Ponowne generowanie miniatur i transkodowanie dużej biblioteki to godziny pracy procesora na małym VPS, podczas których na osi czasu będą widoczne jedynie szare symbole zastępcze. Proces ten można uruchomić ponownie z poziomu Administration > Jobs, ustawiając "Generate Thumbnails" oraz "Transcode Videos" dla brakujących zasobów. Jeśli miejsce docelowe kopii zapasowej na to pozwala, warto je uwzględnić, aby uniknąć oczekiwania. W przypadku zbliżania się do limitu pamięci masowej, należy je pominąć i zaplanować późniejszą przebudowę. Sekcja Sizing an Immich library opisuje, jak duże stają się te foldery w stosunku do plików oryginalnych.
Warto również znać jeszcze jeden folder. UPLOAD_LOCATION/backups przechowuje automatyczne zrzuty bazy danych Immich, tworzone codziennie o godzinie 02:00. Przechowywanych jest 14 ostatnich kopii, co można skonfigurować w Administration > Settings > Backup. Nie zajmują one wiele miejsca i są bardzo przydatne. Znajdują się jednak na tym samym dysku co biblioteka, którą chronią, więc pomagają w przypadku błędnej migracji, ale nie w razie awarii serwera. Należy mimo to wykonywać własne zrzuty, ponieważ zrzut wywołany ręcznie powstaje w tym samym momencie, co migawka plików, z którą jest powiązany.
Wykonanie zrzutu bazy danych
docker exec -t immich_postgres pg_dump --clean --if-exists \
--dbname=immich --username=postgres \
| gzip > /srv/immich/backup/immich.sql.gzZastąp immich oraz postgres swoimi wartościami DB_DATABASE_NAME i DB_USERNAME, jeśli zostały zmienione. --clean --if-exists dodaje DROP ... IF EXISTS przed każdym CREATE, dzięki czemu zrzut jest odtwarzany w bazie danych zawierającej już obiekty, zamiast zatrzymywać się na pierwszym z nich.
Oto szczegół, który często powoduje ciche niepowodzenia skryptów kopii zapasowych. Polecenie to jest potokiem, a powłoka zgłasza kod wyjścia ostatniego polecenia w potoku. Jeśli pg_dump zawiedzie z powodu błędnego hasła lub niedziałającego kontenera, gzip otrzyma pusty strumień, utworzy poprawny plik gzip i zakończy działanie z kodem 0. Skrypt odnotuje sukces, a użytkownik otrzyma 20-bajtową kopię zapasową. Umieść pipefail na początku każdego skryptu kopii zapasowej:
#!/usr/bin/env bash
set -euo pipefailNastępnie sprawdź wynik zamiast polegać na kodzie wyjścia:
ls -lh /srv/immich/backup/immich.sql.gz
gunzip -c /srv/immich/backup/immich.sql.gz | head -n 3Pierwsza linia poprawnego zrzutu zawiera -- PostgreSQL database dump. Plik o rozmiarze kilkuset bajtów oznacza nieudany zrzut, niezależnie od tego, co zgłosił skrypt.
Zapisz informację o wersji kompilacji, która utworzyła zrzut, obok pliku:
docker inspect --format '{{.Config.Image}}' immich_server > /srv/immich/backup/immich-version.txtNie polegaj w tym celu na .env. Standardowy zestaw plików używa IMMICH_VERSION=v3, czyli ruchomego tagu, który podąża za każdym wydaniem 3.x, więc nie dostarcza informacji o tym, która konkretnie kompilacja utworzyła zrzut. Przypnij dokładny tag również w .env.
Wstrzymanie serwera i wykonanie migawki za pomocą restic
Pliki w UPLOAD_LOCATION nie są niezmienne, gdy Immich jest uruchomiony. Serwer zapisuje nowe przesyłane pliki, a zadanie szablonu pamięci masowej przenosi je między katalogami. Jeśli narzędzie do tworzenia kopii zapasowych odczyta plik w trakcie zapisu, zapisze te bajty tak, jakby stanowiły cały plik, a żaden mechanizm nie zgłosi błędu. Zatrzymaj kontener serwera na czas trwania operacji:
docker stop immich_serverPozostaw immich_postgres uruchomione, ponieważ zrzut bazy danych wymaga jego działania. Interfejs WWW oraz aplikacja mobilna będą niedostępne do momentu ponownego uruchomienia serwera, co w przypadku instancji domowej o godzinie 03:00 zazwyczaj nie stanowi problemu.
restic sprawdza się tutaj, ponieważ wykonuje deduplikację i szyfrowanie, zanim jakiekolwiek dane opuszczą serwer. Wskaż repozytorium, które nie znajduje się na tym serwerze:
export RESTIC_REPOSITORY=sftp:backup@backup.example.com:/srv/restic/immich
export RESTIC_PASSWORD_FILE=/root/.restic-password
restic initPamięć obiektowa działa w ten sam sposób i jest lepszym rozwiązaniem, jeśli chcesz całkowicie przenieść kopię poza własny sprzęt:
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 initTen punkt końcowy może być własnym bucketem MinIO na drugiej maszynie lub dowolnym dostawcą zgodnym z S3. Repozytorium znajdujące się na tym samym dysku co biblioteka chroni jedynie przed przypadkowym usunięciem danych.
Następnie wykonaj migawkę, wskazując dokładnie to, co istotne:
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_serverrestic odczytuje całe drzewo plików przy każdym uruchomieniu, ale przesyła tylko te bloki, których wcześniej nie widział. Dzięki temu pierwsza migawka przenosi całą bibliotekę, a każda kolejna tylko zdjęcia dodane w danym dniu.
Retencja oraz klucze, które muszą znajdować się w innym miejscu
restic forget --prune --keep-daily 7 --keep-weekly 5 --keep-monthly 12forget usuwa migawki z indeksu. --prune to część procesu, która usuwa dane, do których te migawki były ostatnim odwołaniem. Uruchomienie forget bez --prune sprawi, że rachunki za przechowywanie danych nigdy nie spadną.
Weryfikacja struktury jest mało kosztowna, dlatego należy ją przeprowadzać raz w tygodniu:
restic checkPotwierdza to spójność metadanych repozytorium. Nie powoduje to odczytu właściwych danych. Raz w miesiącu należy ponownie odczytać próbkę danych i porównać ją z zapisanymi sumami kontrolnymi:
restic check --read-data-subset=5%Jest to jedyna kontrola, która wykrywa cichą korupcję danych w backendzie pamięci masowej, ponieważ pobiera ona rzeczywiste bloki i ponownie oblicza ich sumy kontrolne. Pełne polecenie --read-data dla biblioteki zdjęć oznacza pobranie całego repozytorium, co w przypadku płatnej pamięci obiektowej generuje realne koszty, dlatego w praktyce uruchamia się sprawdzanie wybranego podzbioru danych.
Teraz część, którą użytkownicy często pomijają. Hasło do repozytorium restic jest nie do odzyskania. Nie istnieje funkcja resetowania ani wsparcie techniczne w tym zakresie. Jeśli jedyna kopia hasła znajduje się w /root/.restic-password na serwerze, który próbujesz przywrócić, Twoje kopie zapasowe są jedynie zaszyfrowanym szumem. To samo dotyczy klucza dostępu do pamięci obiektowej oraz DB_PASSWORD z .env. Przechowuj je wszystkie w miejscu niezależnym od działania tej maszyny: wydrukowane w szufladzie lub w menedżerze haseł działającym na innym sprzęcie. Jeśli ten menedżer jest również hostowany samodzielnie, wymaga on takiego samego traktowania, a tworzenie kopii zapasowej Vaultwarden jest osobnym zadaniem.
Przywracanie Immich w poprawnej kolejności
Kolejność przywracania decyduje o tym, czy kopie zapasowe są użyteczne, czy prowadzą do utraty danych. Na nowym hoście należy zachować poniższą sekwencję.
Najpierw przywróć konfigurację. Określa ona wersję oprogramowania oraz ścieżki dostępu.
restic restore latest --target /restore \
--include /srv/immich/.env \
--include /srv/immich/docker-compose.yml \
--include /srv/immich/backupZablokuj wersję przed uruchomieniem czegokolwiek. Przeczytaj immich-version.txt, ustaw IMMICH_VERSION w .env na dokładnie tę samą wersję i na razie zignoruj najnowsze wydanie. Immich nie wspiera procedury downgradu, nawet pomiędzy wersjami poprawkowymi. Jeśli nowszy serwer uruchomi się na bazie ze starszej wersji i wykona migracje, powrót do poprzedniego stanu będzie niemożliwy.
Przywróć dane multimedialne.
restic restore latest --target /restore --include /srv/immich/dataNastępnie przenieś library, upload oraz profile tak, aby znajdowały się bezpośrednio wewnątrz lokalizacji wskazanej przez UPLOAD_LOCATION na nowym hoście. Ścieżka na hoście może ulec zmianie, ponieważ plik compose mapuje ten katalog na stałą ścieżkę wewnątrz kontenera. Struktura wewnątrz tego katalogu musi pozostać niezmieniona.
Uruchom samodzielnie bazę danych. Pozostaw DB_DATA_LOCATION puste, aby Postgres zainicjował nowy klaster.
cd /srv/immich
docker compose pull
docker compose create
docker start immich_postgres
docker exec immich_postgres pg_isready --username=postgrespg_isready wyświetli accepting connections po zakończeniu wstępnej konfiguracji, co zajmuje kilka sekund. docker compose create buduje wszystkie kontenery bez ich uruchamiania i o to właśnie chodzi w tym kroku: serwer Immich nie może jeszcze działać. Serwer, który uruchomi się na pustej bazie, wykona migracje, utworzy nowy schemat i poprosi o utworzenie konta administratora, co uniemożliwi poprawne odtworzenie zrzutu bazy danych.
Wczytaj zrzut bazy danych.
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=onDwa elementy tego polecenia wykonują kluczową pracę. sed jest konieczne, ponieważ pg_dump zapisuje puste search_path w swoim wyjściu jako zabezpieczenie, aby niekwalifikowane nazwy w zrzucie nie odwoływały się do nieoczekiwanego schematu. Typy wektorowe Immich znajdują się w public, więc przy pustej ścieżce wyszukiwania (search path) proces przywracania napotyka pierwszą kolumnę zadeklarowaną jako typ wektorowy, a psql przerywa działanie z błędem ERROR: type "vector" does not exist. Przywrócenie public na ścieżkę rozwiązuje ten problem.
--single-transaction --set ON_ERROR_STOP=on obejmuje cały proces przywracania jedną transakcją, która zostaje przerwana w przypadku wystąpienia pierwszego błędu. Dzięki temu otrzymasz albo kompletną bazę danych, albo nienaruszoną bazę początkową. Bez tego parametru błąd w połowie procesu pozostawi bazę danych, która uruchamia się i pozwala na logowanie, ale brakuje w niej nieokreślonej liczby albumów, co zostanie wykryte dopiero po pewnym czasie.
Teraz uruchom wszystkie usługi.
docker compose up -d
docker compose ps
docker logs -f immich_serverPoczekaj na komunikat startowy w stylu Immich Server is listening on, a następnie otwórz port 2283 i zaloguj się przy użyciu starych danych uwierzytelniających, ponieważ konta użytkowników zostały przywrócone wraz ze zrzutem bazy. Jeśli strona logowania sugeruje utworzenie pierwszego konta administratora, oznacza to, że baza danych nie została poprawnie przywrócona. Zatrzymaj proces i ponownie przeanalizuj wyjście polecenia psql.
Ostrzeżenie dotyczące oficjalnej instrukcji przywracania, która rozpoczyna się od docker compose down -v: polecenie -v usuwa wolumeny nazwane (named volumes). W standardowym pliku compose UPLOAD_LOCATION oraz DB_DATA_LOCATION to dowiązania (bind mounts), więc pozostają nienaruszone. Jeśli jednak którykolwiek z nich został zmieniony na wolumen nazwany, to polecenie usunie Twoje zdjęcia. Przed wykonaniem sprawdź zawartość pliku compose.
Dlaczego oś czasu jest pusta po przywróceniu danych
Oś czasu jest generowana na podstawie wierszy w bazie danych. Immich nigdy nie przeszukuje upload/ podczas uruchamiania w celu ponownego wykrycia zdjęć, ponieważ plik bez przypisanego wiersza nie posiada właściciela, daty ani albumu. Najczęstszym błędem przy przywracaniu jest posiadanie plików przy braku bazy danych. Immich uruchamia się, tworzy pusty schemat i udostępnia działającą instancję, która jest pusta, mimo że dysk jest pełny zdjęć. Nic nie zostało utracone. Nic jednak nie jest widoczne. Rozwiązaniem jest ponowne wczytanie zrzutu bazy danych przy zatrzymanym serwerze, dokładnie w sposób opisany powyżej.
Drugi scenariusz jest mniej oczywisty. Baza danych zostaje przywrócona, oś czasu wypełnia się wpisami, ale każdy zasób nie otwiera się. Oznacza to, że wiersze wskazują na pliki, których kontener nie widzi. Zazwyczaj dzieje się tak, ponieważ library, upload oraz profile znajdują się o jeden poziom za głęboko po restic restore --target /restore, którego nikt nie przeniósł we właściwe miejsce. Zamiast zgadywać, należy sprawdzić zawartość z wnętrza kontenera:
docker exec immich_server ls /dataStandardowy plik compose montuje UPLOAD_LOCATION w /data, więc powyższa lista powinna zawierać library, upload oraz profile. Jeśli wyświetlany jest pusty katalog lub pojedynczy folder srv, oznacza to, że bind mount wskazuje na niewłaściwy poziom, a wiersze w bazie danych są poprawne.
Zgodność wersji kopii zapasowej i przywracania
Projekt Immich publikuje nowe wersje często, a schemat bazy danych zmienia się wraz z nimi. Zrzut bazy danych zawiera schemat wersji serwera, na którym został wykonany.
Przywracanie starszego zrzutu na nowszy serwer zazwyczaj przebiega pomyślnie, ponieważ serwer podczas uruchamiania stosuje oczekujące migracje i aktualizuje schemat. Ta ścieżka jest testowana w ramach sekwencji wydań. Problemy pojawiają się przy przeskakiwaniu kilku głównych wersji jednocześnie. Projekt wprowadza zmiany powodujące niekompatybilność (breaking changes) w głównych wydaniach i dokumentuje je w pliku changelog.
Przywracanie nowszego zrzutu na starszy serwer nie działa. Zrzut zawiera tabele i kolumny, których starszy kod nie obsługuje. Immich nie wspiera procedury obniżania wersji (downgrade), nawet pomiędzy wydaniami typu patch. Nie istnieje polecenie wycofania zmian (rollback).
Bezpieczne przywracanie danych jest procesem powtarzalnym. Należy uruchomić dokładnie tę wersję oprogramowania, która wygenerowała zrzut, zaimportować dane, zalogować się i potwierdzić kompletność osi czasu. Dopiero po tym kroku można wykonać aktualizację. Należy aktualizować oprogramowanie o jedno wydanie na raz, zmieniając wartość IMMICH_VERSION i uruchamiając docker compose pull && docker compose up -d po każdej zmianie. Pomocne jest przechowywanie kopii zapasowych z ostatniego tygodnia: jeśli okaże się, że najnowszy zrzut został wykonany w trakcie nieudanej aktualizacji, w repozytorium dostępna będzie kopia z poprzedniego dnia.
Weryfikacja kopii zapasowej co miesiąc
Kopia zapasowa, której nigdy nie przywrócono, jest jedynie przypuszczeniem. Raz w miesiącu przywróć ją na tymczasowej instancji i sprawdź poprawność zdjęcia. Procedura ta zajmuje około dwudziestu minut i jest jedynym elementem, który zmienia resztę tej strony w plan odzyskiwania danych.
restic snapshots
restic stats latestsnapshots powinno wyświetlić listę ostatniego uruchomienia z poprzedniej nocy. stats latest powinno wskazywać rozmiar zbliżony do rozmiaru biblioteki, a nie zaledwie kilka megabajtów.
Przywróć dane do katalogu tymczasowego, najlepiej na dodatkowym hoście:
restic restore latest --target /tmp/immich-drillSkopiuj docker-compose.yml oraz .env z przywróconego zestawu, a następnie zmień trzy elementy w kopii. Skieruj UPLOAD_LOCATION oraz DB_DATA_LOCATION na katalogi wewnątrz /tmp/immich-drill. Opublikuj port WWW pod innym adresem, 12283:2283 zamiast 2283:2283. Usuń linie container_name:, ponieważ domyślny plik compose ma na sztywno wpisane nazwy, takie jak immich_server, co powoduje konflikt drugiego stosu z pierwszym na tym samym hoście i uniemożliwia Docker utworzenie kontenerów.
Uruchom procedurę przywracania opisaną powyżej: tylko baza danych, wczytanie zrzutu, a następnie docker compose up -d. Teraz wykonaj cztery testy potwierdzające poprawność.
- Zaloguj się przy użyciu hasła stosowanego przed testem. Działające konta oznaczają, że zrzut został poprawnie przywrócony.
- Otwórz oś czasu i przewiń do najstarszego miesiąca. Zasoby w całym zakresie dat oznaczają, że wszystkie wiersze zostały przywrócone, a nie tylko te najnowsze.
- Otwórz jedno zdjęcie w pełnym rozmiarze i pobierz oryginał.
- Porównaj go z tym samym plikiem w aktywnej bibliotece za pomocą
sha256sum. Zgodne sumy kontrolne oznaczają, że dane przetrwały pełny cykl zapisu i odczytu przez restic.
Następnie usuń środowisko testowe za pomocą docker compose down -v w katalogu testowym i usuń /tmp/immich-drill. Zapisz datę w widocznym miejscu, ponieważ wartość tych działań zależy wyłącznie od ich powtórzenia w przyszłym miesiącu. Jeśli nadal wybierasz serwer zdjęć, porównanie PhotoPrism i Immich opisuje różnice między tymi rozwiązaniami właśnie w tym aspekcie.
FAQ
Czy muszę zatrzymywać Immich, aby wykonać kopię zapasową?
Zatrzymaj immich_server, ale pozostaw immich_postgres uruchomione. Baza danych nie wymaga wstrzymania, ponieważ pg_dump odczytuje dane w ramach jednej migawki MVCC i widzi spójny stan niezależnie od trwających zapisów. Powodem zatrzymania są pliki: serwer zapisuje nowe przesyłane dane, a zadanie szablonu przechowywania przenosi pliki między katalogami, więc narzędzie do kopii zapasowych może odczytać plik w trakcie zapisu i zapisać uszkodzoną kopię bez zgłoszenia błędu. docker stop immich_server przed wykonaniem migawki oraz docker start immich_server po niej eliminuje ten wyścig.
Czy mogę skopiować folder danych Postgres zamiast używać pg_dump?
Nie. Kopia działającego katalogu danych odczytuje różne pliki w różnych momentach, więc wynik nie stanowi spójnego stanu, a Postgres odrzuci go przy starcie z błędem PANIC: could not locate a valid checkpoint record lub ulegnie awarii później z powodu uszkodzonej strony. Nawet kopia wykonana przy zatrzymanych usługach jest powiązana z konkretną wersją bazy danych: Immich używa obrazu Postgres 14 z określonymi wersjami rozszerzeń do wyszukiwania wektorowego, a katalog nie otworzy się w innej wersji. Zrzut SQL jest tekstem, który można odtworzyć na dowolnym kompatybilnym serwerze.
Dlaczego moja oś czasu w Immich jest pusta po przywróceniu danych?
Ponieważ oś czasu jest budowana na podstawie wierszy w bazie danych, a pliki zostały przywrócone bez bazy. Immich nigdy nie skanuje upload/ w celu ponownego wykrycia zdjęć, więc pliki bez odpowiadających im wierszy pozostają niewidoczne. Same zdjęcia są nienaruszone. Zatrzymaj serwer, wczytaj zrzut do świeżo zainicjowanego Postgres, a następnie uruchom stos. Jeśli oś czasu jest pełna, ale każde zdjęcie nie otwiera się, problem jest odwrotny: library, upload oraz profile nie znajdują się bezpośrednio w katalogu podpiętym do kontenera. Sprawdź to za pomocą docker exec immich_server ls /data.
Które foldery Immich można pominąć w kopii zapasowej?
thumbs oraz encoded-video generują się ponownie z oryginałów, a DB_DATA_LOCATION odbudowuje się ze zrzutu, więc żaden z nich nie musi znajdować się w zestawie kopii zapasowej. Pominięcie ich oszczędza miejsce przed przywróceniem, ale wydłuża czas po nim, ponieważ odbudowa podglądów i transkodowań dla dużej biblioteki zajmuje godziny pracy procesora, uruchamiane z poziomu Administration > Jobs dla brakujących zasobów. Nigdy nie można pominąć library, upload oraz profile, które przechowują jedyną kopię każdego oryginału.
Czy mogę przywrócić zrzut Immich do nowszej wersji?
Zazwyczaj tak, ponieważ serwer stosuje oczekujące migracje przy starcie i aktualizuje schemat. Odwrotna sytuacja kończy się niepowodzeniem: Immich nie wspiera obniżania wersji, nawet między wydaniami poprawkowymi, więc zrzutu z nowszego wydania nie można wczytać do starszego serwera. Przywróć dane z IMMICH_VERSION przypiętym do wersji, w której wykonano zrzut, potwierdź kompletność osi czasu, a następnie przeprowadź aktualizację. Zapisuj wersję przy każdym zrzucie za pomocą docker inspect --format '{{.Config.Image}}' immich_server, ponieważ domyślny IMMICH_VERSION=v3 to zmienny tag, który nie dostarcza informacji o wersji.