SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor

Cara Backup dan Restore Immich di VPS

Pelajari isi backup Immich, alasan direktori data Postgres aktif bukan backup, serta kesalahan restore yang membuat timeline kosong meski disk tetap penuh.

Hal yang harus ada dalam backup Immich

Backup Immich terdiri atas tiga hal yang diambil pada waktu yang sama. File asli di bawah UPLOAD_LOCATION. Dump SQL database Postgres. .env dan docker-compose.yml yang menjelaskan stack. Pemulihan berarti menerapkan kembali dump tersebut ke database baru saat server Immich dihentikan, lalu hanya menyalakan bagian stack lainnya setelah proses itu selesai. Jika urutannya salah, Immich dapat berjalan tetapi menampilkan timeline kosong, sementara disk tetap penuh.

Pemisahan ini penting karena Immich menyimpan statusnya di dua tempat yang tidak saling mengetahui. Postgres menyimpan setiap album, setiap cluster wajah, setiap tautan bersama, setiap akun pengguna dan kunci API, serta path tersimpan untuk setiap aset. Sistem file menyimpan data piksel. Jika file dipulihkan tanpa database, Immich tidak menampilkan apa pun. Jika database dipulihkan tanpa file, setiap aset akan terbuka sebagai gambar rusak.

Perintah di sini ditulis untuk Immich v3.1.0, yaitu rilis yang berlaku pada awal Agustus 2026. Per 2026-10-21, rilis saat ini adalah v3.3.4, yang diterbitkan pada 2026-10-20, dan file compose, image database, serta langkah backup dan pemulihan yang didokumentasikan masih sesuai dengan yang digunakan halaman ini. Proyek ini merilis pembaruan dengan cepat, dan prosedur backup yang didokumentasikan telah berubah beberapa kali. Karena itu, periksa versi yang benar-benar Anda jalankan sebelum menyalin apa pun. Jika stack belum berjalan, mulai dari panduan instalasi Immich lalu kembali ke sini.

Pahami tujuan setiap path

Dua variabel dalam .env menentukan seluruh konfigurasi pada halaman ini. UPLOAD_LOCATION adalah direktori induk tempat Immich menyimpan semua media. DB_DATA_LOCATION adalah direktori data Postgres.

example.env bawaan menetapkan UPLOAD_LOCATION=./library. Nilai default ini membingungkan karena Immich kemudian membuat folder bernama library di dalam direktori tersebut. File asli Anda akhirnya berada di ./library/library. Tetapkan path absolut agar skrip pencadangan tidak pernah bergantung pada direktori tempat Anda menjalankannya.

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

Di dalam UPLOAD_LOCATION, Immich membuat beberapa folder. Tiga di antaranya berisi data yang tidak dapat dibuat ulang oleh tugas apa pun:

  • library: file asli yang disusun berdasarkan template penyimpanan Anda
  • upload: file asli yang belum dipindahkan ke tata letak berdasarkan template, serta unggahan yang masih diproses
  • profile: foto profil pengguna

Jika library hilang, foto tersebut juga hilang. Immich tidak menyimpan salinan kedua file asli di tempat lain.

Mengapa menyalin direktori data Postgres bukan backup

DB_DATA_LOCATION tampak seperti target yang mudah. Direktori tersebut dapat disalin dengan rsync, dan proses penyalinan selesai tanpa error. Jika direktori disalin saat Postgres sedang berjalan, hasilnya bukan backup. Jika disalin saat Postgres dihentikan, hasilnya merupakan backup, tetapi rentan. Berikut dua alasannya, dan Anda dapat melihat kegagalan pada kedua kondisi tersebut.

Alasan pertama adalah ketidakkonsistenan data. Postgres terlebih dahulu menulis setiap perubahan ke write-ahead log (WAL), lalu menerapkannya ke file tabel pada checkpoint. Jadi, pada setiap saat, file di disk dapat berada dalam keadaan belum konsisten. Proses penyalinan bertahap yang berlangsung selama empat menit dapat membaca file pertama pada 02:00 dan file terakhir pada 02:04. Kedua file tersebut tidak berasal dari transaksi yang sama. Saat Postgres dijalankan menggunakan hasil penyalinan itu, Postgres akan menolak memulai dengan PANIC: could not locate a valid checkpoint record, atau memulai lalu berhenti ketika pertama kali membaca page yang rusak dengan invalid page in block 1234 of relation base/16384/.... Hasil penyalinan tersebut tidak dapat dipulihkan dengan cara apa pun.

Alasan kedua berkaitan dengan penyalinan yang dilakukan saat semua proses dihentikan. PostgreSQL mendokumentasikan bahwa penyalinan lengkap direktori data yang telah dimatikan merupakan backup yang valid, tetapi direktori tersebut hanya dapat dibuka oleh binary yang menggunakan format penyimpanan yang sama. Immich menetapkan image database berdasarkan digest, yaitu ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0 saat ini. Image tersebut menggunakan Postgres 14 dengan ekstensi pencarian vektor VectorChord, pgvector, dan pgvecto.rs yang sudah terpasang. Rilis minor Postgres 14 yang lebih baru dapat membuka direktori tersebut tanpa perubahan, tetapi versi mayor Postgres yang berbeda tidak dapat membukanya. Ekstensi yang menjadi dependensi tabel Anda juga harus tersedia dalam versi yang kompatibel. Host pemulihan harus menjalankan image yang kompatibel. SQL dump tidak memiliki keterbatasan tersebut: isinya berupa teks, dan server yang kompatibel dapat memutarnya kembali.

pg_dump mengatasi masalah ketidakkonsistenan data secara langsung. Perintah tersebut membaca seluruh database dalam satu snapshot MVCC (multi-version concurrency control), sehingga melihat database persis seperti pada satu waktu tertentu sementara proses penulisan lain tetap berlangsung. Karena itu, Anda tidak perlu menghentikan Postgres untuk membuat dump.

Yang dapat dikecualikan dari backup

Data berikut dapat dibuat ulang, jadi Anda dapat melewatinya:

  • thumbs: gambar pratinjau dan thumbnail
  • encoded-video: video yang ditranskode
  • DB_DATA_LOCATION: dibuat ulang dari dump
  • volume Docker model-cache: model machine learning, diunduh ulang saat diperlukan

Melewati data ini adalah kompromi, bukan keuntungan tanpa konsekuensi. Membuat ulang thumbnail dan hasil transkode untuk library besar dapat menggunakan CPU selama berjam-jam pada VPS kecil, dan timeline akan menampilkan placeholder abu-abu selama proses tersebut. Jalankan kembali prosesnya melalui Administration > Jobs, dengan "Generate Thumbnails" dan "Transcode Videos" diatur agar berjalan pada aset yang belum tersedia. Jika target backup Anda memiliki ruang, sertakan data tersebut dan hindari waktu tunggu. Jika Anda hampir mencapai batas penyimpanan, kecualikan data tersebut dan rencanakan proses pembuatan ulang. Menentukan ukuran library Immich menjelaskan pertumbuhan ukuran folder-folder ini dibandingkan dengan file asli.

Ada satu folder lain yang perlu Anda ketahui. UPLOAD_LOCATION/backups berisi dump database otomatis milik Immich, yang ditulis setiap hari pada 02:00 dan menyimpan 14 dump terakhir. Pengaturan ini dapat dikonfigurasi melalui Administration > Settings > Database Dump Settings. Dump tersebut tidak membebani Anda secara finansial dan benar-benar berguna. Dump tersebut juga berada pada disk yang sama dengan library yang dilindunginya, sehingga berguna untuk menangani migrasi yang gagal, tetapi tidak untuk menangani server yang mati. Tetap buat dump Anda sendiri, karena dump yang Anda picu sendiri dibuat pada saat yang sama dengan snapshot file yang terkait dengannya.

Ambil dump database

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

Ganti immich dan postgres dengan DB_DATABASE_NAME dan DB_USERNAME jika Anda mengubahnya. --clean --if-exists menambahkan DROP ... IF EXISTS di depan setiap CREATE. Dengan demikian, dump dapat dipulihkan ke database yang sudah berisi objek tanpa berhenti pada objek pertama.

Berikut detail yang sering merusak script backup tanpa terlihat. Perintah tersebut merupakan pipeline. Shell melaporkan status keluar dari perintah terakhir dalam pipeline. Jika pg_dump gagal karena password salah atau container tidak berjalan, gzip menerima stream kosong, menulis file gzip yang valid, lalu keluar dengan status 0. Script Anda mencatat keberhasilan, tetapi backup yang dihasilkan hanya berukuran 20 byte. Letakkan pipefail di bagian awal setiap script backup:

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

Kemudian periksa hasilnya, bukan hanya mengandalkan kode keluar:

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

Baris pertama dump yang sehat berisi -- PostgreSQL database dump. File berukuran beberapa ratus byte menunjukkan dump gagal, apa pun yang dilaporkan oleh script.

Catat release yang menulis dump tersebut di samping file dump dengan meminta informasi dari server yang sedang berjalan:

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

Endpoint tersebut tidak memerlukan login dan mengembalikan release yang sedang berjalan dalam bentuk nomor major, minor, dan patch. Dengan demikian, 3, 1, dan 0 berarti v3.1.0. Jangan mengandalkan .env untuk hal ini. Jangan mengandalkan docker inspect --format '{{.Config.Image}}' immich_server juga, karena nilai tersebut hanya menampilkan image reference yang Anda konfigurasi. File bawaan menetapkan IMMICH_VERSION=v3, yaitu tag yang berubah-ubah dan mengikuti setiap release 3.x. Karena itu, catatan yang berakhir dengan :v3 tidak memberi tahu build yang sebenarnya menulis dump. Tetapkan tag yang persis di .env juga.

Jedaikan server, lalu buat snapshot dengan restic

File di bawah UPLOAD_LOCATION tidak bersifat immutable selama Immich berjalan. Server menulis upload baru, dan tugas template penyimpanan memindahkan file antar-direktori. Jika alat backup membaca file saat penulisan belum selesai, alat tersebut menyimpan byte yang sudah terbaca seolah-olah itu seluruh file, tanpa melaporkan error. Hentikan container server selama proses berlangsung:

docker stop immich_server

Biarkan immich_postgres tetap berjalan karena dump memerlukannya. Antarmuka web dan aplikasi mobile akan offline sampai server dijalankan kembali. Pada instance rumah tangga yang berjalan pukul 03:00, kondisi ini biasanya tidak menjadi masalah.

restic sesuai untuk kebutuhan ini karena melakukan deduplikasi dan enkripsi sebelum data meninggalkan server. Arahkan restic ke repository yang tidak berada di server ini:

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

Object storage bekerja dengan cara yang sama dan merupakan pilihan yang lebih baik jika Anda ingin salinan berada sepenuhnya di luar perangkat keras milik sendiri:

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

Endpoint tersebut dapat berupa bucket MinIO yang Anda jalankan sendiri pada mesin kedua atau provider yang kompatibel dengan S3. Repository pada disk yang sama dengan library hanya melindungi Anda dari penghapusan yang keliru, bukan dari risiko lainnya.

Selanjutnya, buat snapshot yang mencantumkan semua hal penting:

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 membaca seluruh tree pada setiap proses, tetapi hanya mengunggah blok yang belum pernah dilihat sebelumnya. Karena itu, snapshot pertama memindahkan seluruh library Anda, sedangkan setiap snapshot berikutnya hanya memindahkan foto baru pada hari tersebut.

Retensi dan kunci yang harus disimpan di tempat lain

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

forget menghapus snapshot dari indeks. --prune adalah bagian yang menghapus data yang sebelumnya hanya dirujuk oleh snapshot tersebut. Jalankan forget tanpa --prune, dan biaya penyimpanan Anda tidak akan pernah turun.

Pemeriksaan struktur tidak mahal, jadi jalankan sekali setiap minggu:

restic check

Pemeriksaan ini memastikan metadata repository konsisten. Pemeriksaan ini tidak membaca data Anda. Sekali sebulan, baca ulang sampel data dan periksa kecocokannya dengan hash yang tercatat:

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

Ini adalah satu-satunya pemeriksaan yang dapat mendeteksi kerusakan senyap pada backend penyimpanan, karena pemeriksaan ini mengunduh blok nyata dan menghitung ulang checksum-nya. --read-data penuh pada pustaka foto berarti mengunduh seluruh repository. Pada object storage dengan biaya berdasarkan penggunaan, hal ini memerlukan biaya nyata. Karena itu, subset bergilir adalah cara yang benar-benar digunakan.

Sekarang bagian yang sering dilewatkan. Password repository restic tidak dapat dipulihkan. Tidak ada reset dan tidak ada tiket dukungan. Jika satu-satunya salinan berada di /root/.restic-password pada server yang sedang Anda coba pulihkan, backup Anda hanya menjadi data terenkripsi yang tidak berguna. Hal yang sama berlaku untuk access key object storage dan DB_PASSWORD dari .env. Simpan semuanya di tempat yang tidak bergantung pada mesin ini tetap aktif: cetak dan simpan di laci, atau gunakan password manager yang berjalan pada hardware berbeda. Jika password manager tersebut juga di-host sendiri, perlakuannya harus sama, dan mencadangkan Vaultwarden merupakan tugas tersendiri.

Pulihkan Immich dalam urutan yang benar

Urutan pemulihan menentukan apakah backup yang baik menghasilkan timeline yang lengkap atau kosong. Ikuti urutan ini pada host baru.

Pulihkan konfigurasi terlebih dahulu. Konfigurasi menunjukkan versi yang harus dijalankan dan lokasi path yang digunakan.

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

Tetapkan versinya sebelum menjalankan apa pun. Baca immich-version.txt, tetapkan IMMICH_VERSION di .env ke rilis tersebut (v3.1.0 untuk major 3, minor 1, patch 0), dan untuk sementara jangan gunakan rilis terbaru. Immich tidak mendukung downgrade, bahkan antarpatch, sehingga jika server yang lebih baru berjalan menggunakan dump yang lebih lama dan menjalankan migrasinya, Anda tidak dapat mengembalikannya.

Pulihkan media.

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

Kemudian pindahkan library, upload, dan profile agar berada langsung di dalam lokasi yang ditunjuk oleh UPLOAD_LOCATION pada host ini. Path pada host boleh berubah karena compose file memetakan direktori tersebut ke path tetap di dalam container. Struktur di dalamnya tidak boleh berubah.

Jalankan database secara terpisah. Biarkan DB_DATA_LOCATION kosong agar Postgres menginisialisasi cluster baru.

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

pg_isready menampilkan accepting connections setelah penyiapan pertama selesai, yang memerlukan waktu beberapa detik. docker compose create membuat semua container tanpa menjalankannya. Itulah tujuan langkah ini: server Immich belum boleh berjalan. Server yang berjalan dengan database kosong akan menerapkan migrasi, membuat schema baru, dan meminta Anda membuat akun admin baru. Setelah itu, Anda akan memulihkan dump ke aplikasi yang sedang berjalan.

Pulihkan dump.

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

Dua bagian pada perintah tersebut menjalankan fungsi penting. sed diperlukan karena pg_dump menulis search_path kosong ke dalam outputnya sebagai langkah pengamanan. Dengan demikian, nama yang tidak memenuhi syarat dalam dump tidak dapat mengarah ke schema yang tidak diharapkan. Tipe pencarian vektor Immich berada di public. Jika search path kosong, proses pemulihan mencapai kolom pertama yang dideklarasikan dengan tipe vector, lalu psql berhenti dengan ERROR: type "vector" does not exist. Menambahkan kembali public ke dalam path akan memperbaikinya.

--single-transaction --set ON_ERROR_STOP=on membungkus seluruh proses pemulihan dalam satu transaksi yang dibatalkan saat terjadi error pertama. Hasilnya adalah database yang pulih sepenuhnya atau database yang tidak berubah. Tanpa opsi ini, kegagalan di tengah proses akan meninggalkan database yang dapat berjalan dan menerima login Anda, tetapi kehilangan album dalam jumlah yang tidak diketahui. Anda mungkin baru menyadarinya beberapa minggu kemudian.

Sekarang jalankan semuanya.

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

Tunggu baris startup seperti Immich Server is listening on, lalu buka port 2283 dan login menggunakan kredensial lama Anda karena akun pengguna ikut dipulihkan bersama dump. Jika halaman login justru menawarkan pembuatan akun admin pertama, database belum dipulihkan. Hentikan proses dan baca kembali output psql.

Perhatikan satu hal tentang petunjuk pemulihan resmi melalui command line, yang diawali dengan docker compose down -v. -v menghapus named volume. Pada compose file bawaan, UPLOAD_LOCATION dan DB_DATA_LOCATION adalah bind mount sehingga tetap ada. Jika salah satunya Anda ubah menjadi named volume, perintah tersebut akan menghapus foto Anda. Baca compose file sebelum menjalankan perintah itu.

Mengapa timeline kosong setelah pemulihan

Timeline dibuat dari baris database. Immich tidak pernah menelusuri upload/ saat boot untuk menemukan kembali foto, karena file tanpa baris database tidak memiliki pemilik, tanggal, atau album. Jadi, pemulihan yang paling sering bermasalah adalah file sudah dipulihkan, tetapi database hilang. Immich berjalan, membuat skema kosong, lalu memberi Anda instance yang berfungsi tetapi tidak berisi apa pun, sementara disk penuh dengan foto Anda. Tidak ada yang hilang. Namun, tidak ada yang dapat ditampilkan. Solusinya adalah menjalankan kembali dump saat server dihentikan, persis seperti di atas.

Versi kedua lebih sulit dideteksi. Database berhasil dipulihkan, timeline terisi entri, tetapi setiap aset gagal dibuka. Artinya, baris database menunjuk ke file yang tidak dapat dilihat oleh container. Biasanya ini terjadi karena library, upload, dan profile berada satu tingkat terlalu dalam setelah sebuah restic restore --target /restore yang tidak dipindahkan ke lokasi yang benar. Periksa dari dalam container, bukan dengan menebak:

docker exec immich_server ls /data

File compose bawaan me-mount UPLOAD_LOCATION ke /data, sehingga daftar tersebut seharusnya menampilkan library, upload, dan profile. Jika yang ditampilkan adalah direktori kosong atau folder srv yang tidak semestinya ada, bind mount Anda mengarah ke tingkat direktori yang salah dan baris database tersebut tidak bermasalah.

Kecocokan versi antara backup dan pemulihan

Immich sering merilis versi baru, dan schema ikut berubah. Karena itu, dump membawa schema dari server yang membuatnya.

Memulihkan dump yang lebih lama ke server yang lebih baru biasanya berhasil karena server menerapkan migration yang masih tertunda saat start, lalu memperbarui schema secara bertahap. Jalur ini diuji di sepanjang urutan rilis. Masalah biasanya muncul saat beberapa versi mayor dilewati sekaligus. Project mempertahankan perubahan yang tidak kompatibel pada rilis mayor dan mendokumentasikannya dalam changelog.

Memulihkan dump yang lebih baru ke server yang lebih lama sama sekali tidak berhasil. Dump tersebut berisi tabel dan kolom yang tidak dikenali oleh kode versi lama. Immich juga menyatakan bahwa downgrade tidak didukung, bahkan di antara versi patch. Tidak ada command rollback yang dapat digunakan.

Jadi, pemulihan yang aman harus dilakukan secara sederhana. Jalankan versi yang sama persis dengan versi yang membuat dump, pulihkan dump tersebut, login, lalu pastikan timeline sudah lengkap. Setelah itu, lakukan upgrade. Upgrade satu rilis setiap kali, dengan menaikkan IMMICH_VERSION dan menjalankan docker compose pull && docker compose up -d setelah setiap peningkatan. Menyimpan dump selama satu minggu juga membantu. Jika dump terbaru ternyata dibuat saat upgrade gagal, dump dari kemarin masih tersedia di repository.

Verifikasi backup setiap bulan

Backup yang belum pernah dipulihkan hanyalah perkiraan. Sebulan sekali, pulihkan backup tersebut ke instance sementara yang dapat dibuang, lalu lihat sebuah foto. Latihan ini memerlukan waktu sekitar twenty minutes dan merupakan satu-satunya cara untuk mengubah seluruh isi halaman ini menjadi rencana pemulihan.

restic snapshots
restic stats latest

snapshots harus menampilkan eksekusi tadi malam. stats latest harus melaporkan ukuran yang mendekati ukuran library Anda, bukan hanya beberapa megabyte.

Pulihkan ke direktori sementara, idealnya pada host cadangan:

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

Salin docker-compose.yml dan .env dari set yang dipulihkan, lalu ubah tiga hal pada salinan tersebut. Arahkan UPLOAD_LOCATION dan DB_DATA_LOCATION ke direktori di bawah /tmp/immich-drill. Publikasikan port web di lokasi lain, yaitu 12283:2283, bukan 2283:2283. Hapus baris container_name: karena file compose bawaan menetapkan nama seperti immich_server secara hard-code. Akibatnya, stack kedua pada host yang sama bertabrakan dengan stack pertama dan Docker menolak membuatnya.

Jalankan urutan pemulihan dari bagian sebelumnya: database saja, putar ulang dump, lalu docker compose up -d. Sekarang lakukan empat pemeriksaan berikut untuk membuktikan bahwa pemulihan berhasil.

  1. Login dengan password yang Anda gunakan sebelum latihan. Akun yang dapat digunakan berarti dump berhasil dipulihkan.
  2. Buka timeline dan gulir ke bulan paling lama. Aset yang mencakup seluruh rentang tanggal berarti semua baris telah dipulihkan, bukan hanya data terbaru.
  3. Buka satu foto dalam ukuran penuh dan unduh file aslinya.
  4. Bandingkan file tersebut dengan file yang sama di library aktif menggunakan sha256sum. Hash yang cocok berarti byte tetap utuh setelah melewati proses pemulihan dengan restic.

Kemudian hapus lingkungan latihan menggunakan docker compose down -v di direktori latihan dan hapus /tmp/immich-drill. Catat tanggalnya di tempat yang mudah Anda lihat karena manfaat latihan ini sepenuhnya bergantung pada pelaksanaannya kembali bulan depan. Jika Anda masih menentukan server foto yang akan digunakan, perbandingan PhotoPrism dan Immich membahas perbedaan keduanya secara khusus dalam hal ini.

FAQ

Apakah saya harus menghentikan Immich untuk membuat backup?

Hentikan immich_server dan biarkan immich_postgres tetap berjalan. Database tidak perlu dihentikan sementara karena pg_dump membaca data dalam satu snapshot MVCC dan melihat satu keadaan yang konsisten, terlepas dari proses lain yang sedang menulis. File adalah alasan server harus dihentikan: server menulis upload baru dan storage template job memindahkan file antardirektori, sehingga alat backup dapat membaca file di tengah proses penulisan dan menyimpan salinan yang terpotong tanpa error. docker stop immich_server sebelum snapshot dan docker start immich_server setelahnya menghilangkan kondisi balapan tersebut.

Dapatkah saya menyalin folder data Postgres tanpa menjalankan pg_dump?

Tidak saat Postgres sedang berjalan. Penyalinan bertahap terhadap direktori data aktif membaca file yang berbeda pada waktu yang berbeda, sehingga hasilnya bukan satu keadaan yang konsisten. Postgres akan menolaknya saat startup dengan PANIC: could not locate a valid checkpoint record atau gagal kemudian karena halaman yang rusak. Salinan lengkap yang dibuat saat Postgres dihentikan merupakan backup yang valid, tetapi hanya dapat dibuka oleh major version Postgres yang sama dengan extension yang kompatibel. Immich menetapkan image Postgres 14 yang berisi VectorChord, pgvector, dan pgvecto.rs. Direktori tersebut tidak dapat dibuka oleh major version yang berbeda. SQL dump berupa teks biasa dan dapat dipulihkan ke server kompatibel mana pun, sehingga tetap menjadi salinan yang harus disimpan.

Mengapa timeline Immich kosong setelah pemulihan?

Karena timeline dibangun dari baris database, sedangkan Anda memulihkan file tanpa database. Immich tidak pernah memindai upload/ untuk menemukan kembali foto, sehingga file tanpa baris database tetap tidak terlihat. Foto itu sendiri tidak berubah. Hentikan server, pulihkan dump ke Postgres yang baru diinisialisasi, lalu jalankan kembali stack. Jika timeline penuh tetapi semua foto gagal dibuka, masalahnya terbalik: library, upload, dan profile tidak berada langsung di dalam direktori yang di-bind ke container. Periksa dengan docker exec immich_server ls /data.

Folder Immich mana yang dapat dilewati dalam backup?

thumbs dan encoded-video dapat dibuat ulang dari file asli, sedangkan DB_DATA_LOCATION dapat dibuat ulang dari dump. Karena itu, folder-folder tersebut tidak harus disertakan dalam set backup. Melewatkannya menghabiskan waktu setelah pemulihan, bukan ruang penyimpanan sebelumnya, karena pembuatan ulang preview dan transcode untuk pustaka besar dapat memerlukan waktu berjam-jam serta CPU. Jalankan proses tersebut dari Administration > Jobs untuk aset yang hilang. Yang tidak boleh dilewati adalah library, upload, dan profile karena ketiganya menyimpan satu-satunya salinan setiap file asli.

Dapatkah saya memulihkan dump Immich ke versi yang lebih baru?

Biasanya ya, karena server menerapkan migration yang tertunda saat startup dan memperbarui schema secara bertahap. Proses sebaliknya gagal: Immich tidak mendukung downgrade, bahkan di antara patch release, sehingga dump dari release yang lebih baru tidak dapat dimuat ke server yang lebih lama. Lakukan pemulihan dengan IMMICH_VERSION yang ditetapkan ke release yang membuat dump tersebut, pastikan timeline lengkap, lalu lakukan upgrade. Catat release di samping setiap dump menggunakan curl -fsS http://localhost:2283/api/server/version karena docker inspect hanya menampilkan image reference yang dikonfigurasi. Nilai default IMMICH_VERSION=v3 adalah floating tag yang tidak memberikan informasi versi.