VPS-এ Immich ব্যাকআপ ও রিস্টোর করার সঠিক পদ্ধতি
Immich ব্যাকআপে মূল ফাইল, SQL dump ও stack ফাইল কেন একসঙ্গে দরকার, Postgres data directory কপি কেন যথেষ্ট নয় এবং restore-এ timeline খালি হওয়ার ভুলটি জানুন।
Immich ব্যাকআপে যা থাকতে হবে
একটি Immich ব্যাকআপে একই সময়ে সংরক্ষিত তিনটি জিনিস থাকতে হবে। UPLOAD_LOCATION-এর অধীনে থাকা মূল ফাইল। Postgres database-এর একটি SQL dump। Stack বর্ণনা করা .env এবং docker-compose.yml। Restore করার অর্থ হলো Immich server বন্ধ থাকা অবস্থায় সেই dump একটি নতুন database-এ পুনরায় প্রয়োগ করা, এবং এর পরেই stack-এর বাকি অংশ চালু করা। ক্রম ভুল হলে পূর্ণ disk-এর ওপর খালি timeline দেখানো একটি সচল Immich পাবেন।
এই বিভাজন গুরুত্বপূর্ণ, কারণ Immich এমন দুটি স্থানে state সংরক্ষণ করে, যেগুলো একে অপরের বিষয়ে কিছু জানে না। Postgres-এ প্রতিটি album, প্রতিটি face cluster, প্রতিটি shared link, প্রতিটি user account ও API key এবং প্রতিটি asset-এর সংরক্ষিত path থাকে। Filesystem-এ pixel থাকে। Database ছাড়া file restore করলে Immich কিছুই দেখাবে না। File ছাড়া database restore করলে প্রতিটি asset খুললে broken image দেখা যাবে।
এখানের command-গুলো Immich v3.1.0 অনুযায়ী লেখা হয়েছে, যা 2026 সালের August-এর শুরুর দিকে বর্তমান release ছিল। Project দ্রুত নতুন release প্রকাশ করে, এবং নথিবদ্ধ backup procedure একাধিকবার পরিবর্তিত হয়েছে। তাই কিছু copy করার আগে আপনি আসলে কোন version চালাচ্ছেন তা যাচাই করুন। Stack এখনও চালু না থাকলে Immich install guide-টি দিয়ে শুরু করে পরে এখানে ফিরে আসুন।
আপনার path কোন অবস্থান নির্দেশ করে তা জানুন
.env-এর দুটি variable এই পৃষ্ঠার সবকিছু নির্ধারণ করে। UPLOAD_LOCATION হলো parent directory, যেখানে Immich সব media লেখে। DB_DATA_LOCATION হলো Postgres data directory।
স্টক example.env-এ UPLOAD_LOCATION=./library সেট করা থাকে। এটি বিভ্রান্তিকর default, কারণ Immich এরপর এর ভেতরে library নামে একটি folder তৈরি করে। আপনার original ফাইলগুলো ./library/library-এ জমা হয়। এর পরিবর্তে একটি absolute path সেট করুন, যাতে backup script কখনো আপনি কোন directory থেকে এটি চালিয়েছেন তার ওপর নির্ভর না করে।
UPLOAD_LOCATION=/srv/immich/data
DB_DATA_LOCATION=/srv/immich/postgres
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
IMMICH_VERSION=v3.1.0UPLOAD_LOCATION-এর ভেতরে Immich কয়েকটি folder তৈরি করে। এর মধ্যে তিনটিতে এমন data থাকে, যা কোনো job পুনর্নির্মাণ করতে পারে না:
library: storage template অনুযায়ী সাজানো original ফাইলupload: template layout-এ এখনো সরানো হয়নি এমন original ফাইল এবং চলমান uploadprofile: user profile picture
library হারালে photo-টি হারিয়ে যাবে। Immich কোনো original-এর দ্বিতীয় copy অন্য কোথাও রাখে না।
কেন Postgres data directory কপি করা backup নয়
DB_DATA_LOCATION-কে সহজ লক্ষ্য বলে মনে হতে পারে। এটি একটি directory, rsync এটি কপি করবে, এবং কোনো error ছাড়াই কপি শেষ হবে। তবুও এটি backup নয়। এর দুটি কারণ পরীক্ষা করলে ব্যর্থতা দেখা যায়।
প্রথম কারণটি হলো tearing। Postgres প্রতিটি পরিবর্তন প্রথমে write-ahead log (WAL)-এ লেখে। এরপর checkpoint-এর সময় table file-এ তা প্রয়োগ করে। তাই যেকোনো মুহূর্তে disk-এর file-গুলো পরিবর্তনের মধ্যবর্তী অবস্থায় থাকে। চার মিনিট সময় নেওয়া rolling copy প্রথম file-টি 02:00-এ এবং শেষ file-টি 02:04-এ পড়ে। এই দুই file একই transaction-এর অংশ নয়। ফলাফলের ওপর Postgres চালু করলে startup-এর সময় PANIC: could not locate a valid checkpoint record দেখিয়ে এটি কাজ প্রত্যাখ্যান করতে পারে। অথবা চালু হওয়ার পর ক্ষতিগ্রস্ত page প্রথমবার পড়ার সময় invalid page in block 1234 of relation base/16384/... দেখিয়ে বন্ধ হয়ে যেতে পারে। ওই copy থেকে কোনো অবস্থাই পুনরুদ্ধার করা যায় না।
সবকিছু আগে বন্ধ করলেও দ্বিতীয় কারণটি থেকেই যায়। Postgres data directory যে exact binary এটি লিখেছে, তার সঙ্গে আবদ্ধ। Immich বর্তমানে ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0 digest ব্যবহার করে তার database image নির্দিষ্ট করে। এটি Postgres 14, যাতে vector-search-এর জন্য দুটি extension compile করা আছে। ওই build দ্বারা লেখা data directory ভিন্ন Postgres major version-এর অধীনে open হবে না। ভিন্ন extension version-যুক্ত build-এর অধীনেও এটি open হবে না। Restore host-কে image-টি হুবহু পুনরুৎপাদন করতে হবে। SQL dump-এর ক্ষেত্রে এই সীমাবদ্ধতা নেই। এটি text, এবং যেকোনো compatible server এটি পুনরায় প্রয়োগ করতে পারে।
pg_dump সরাসরি tearing সমস্যাটি এড়িয়ে যায়। এটি একটি একক MVCC (multi-version concurrency control) snapshot-এর মধ্যে পুরো database পড়ে। ফলে অন্য write চলতে থাকলেও এটি database-কে একটি নির্দিষ্ট মুহূর্তের অবস্থা হিসেবে দেখে। তাই dump নেওয়ার জন্য Postgres বন্ধ করতে হয় না।
ব্যাকআপে যা বাদ দিতে পারেন
এগুলো পুনরায় তৈরি করা যায়, তাই চাইলে বাদ দিতে পারেন:
thumbs: preview এবং thumbnail imageencoded-video: transcoded videoDB_DATA_LOCATION: dump থেকে পুনর্নির্মাণ করা হয়model-cacheDocker volume: machine learning model, প্রয়োজন হলে আবার download করা যাবে
এগুলো বাদ দেওয়া একটি সমঝোতা; এটি বিনা খরচের সুবিধা নয়। বড় library-এর thumbnail এবং transcode পুনর্নির্মাণ করতে ছোট VPS-এ কয়েক ঘণ্টা CPU সময় লাগতে পারে, এবং পুরো সময় timeline-এ ধূসর placeholder দেখা যাবে। Administration > Jobs থেকে এগুলো আবার চালান। সেখানে "Generate Thumbnails" এবং "Transcode Videos" এমনভাবে সেট করুন, যাতে missing asset-এর ক্ষেত্রে কাজ চলে। আপনার backup target-এ জায়গা থাকলে এগুলো অন্তর্ভুক্ত করুন এবং অপেক্ষা এড়িয়ে চলুন। storage limit-এর কাছাকাছি থাকলে এগুলো বাদ দিন এবং পুনর্নির্মাণের পরিকল্পনা রাখুন। Immich library-এর আকার নির্ধারণ-এ মূল file-এর তুলনায় এই folder-গুলো কত বড় হয়, তা ব্যাখ্যা করা হয়েছে।
আরেকটি folder সম্পর্কে জানা উপকারী। UPLOAD_LOCATION/backups-এ Immich-এর নিজস্ব automatic database dump থাকে। এগুলো প্রতিদিন 02:00-এ লেখা হয় এবং সর্বশেষ 14টি রাখা হয়। Administration > Settings > Backup থেকে এই সংখ্যা ও আচরণ configure করা যায়। এগুলোর জন্য অতিরিক্ত storage খরচ হয় না এবং এগুলো সত্যিই কার্যকর। তবে এগুলো যে library-কে সুরক্ষিত রাখে, সেই একই disk-এ থাকে। তাই এগুলো ব্যর্থ migration-এর ক্ষেত্রে সহায়তা করে, কিন্তু server নষ্ট হলে নয়। তবু নিজে একটি dump নিন, কারণ আপনি নিজে যে dump চালু করেন, সেটি তার সঙ্গে সম্পর্কিত file snapshot-এর একই সময়ে তৈরি হয়।
ডেটাবেস dump নিন
docker exec -t immich_postgres pg_dump --clean --if-exists \
--dbname=immich --username=postgres \
| gzip > /srv/immich/backup/immich.sql.gzআপনি এগুলো পরিবর্তন করে থাকলে immich এবং postgres-এর জায়গায় আপনার DB_DATABASE_NAME এবং DB_USERNAME বসান। --clean --if-exists প্রতিটি CREATE-এর সামনে একটি DROP ... IF EXISTS বসায়। ফলে dump এমন একটি ডেটাবেসে পুনরায় প্রয়োগ হয়, যেখানে ইতিমধ্যে object আছে; প্রথম object-এ গিয়ে প্রক্রিয়া বন্ধ হয়ে যায় না।
এখন সেই বিষয়টি দেখুন, যা backup script-কে নীরবে নষ্ট করে। ওই command একটি pipeline, এবং shell pipeline-এর শেষ command-এর exit status রিপোর্ট করে। ভুল password ব্যবহার করলে বা container চলমান না থাকলে pg_dump ব্যর্থ হতে পারে। সে ক্ষেত্রে gzip একটি খালি stream পায়, বৈধ gzip file লিখে এবং 0 exit status দিয়ে শেষ হয়। আপনার script success log করে, কিন্তু আপনার কাছে 20-byte-এর একটি backup থাকে। প্রতিটি backup script-এর শুরুতে pipefail রাখুন:
#!/usr/bin/env bash
set -euo pipefailএরপর exit code-এর ওপর নির্ভর না করে ফলাফল পরীক্ষা করুন:
ls -lh /srv/immich/backup/immich.sql.gz
gunzip -c /srv/immich/backup/immich.sql.gz | head -n 3সঠিক dump-এর প্রথম line হলো -- PostgreSQL database dump। File-এর আকার কয়েকশো byte হলে script যা-ই বলুক, dump ব্যর্থ হয়েছে।
Dump-এর পাশে কোন build এটি লিখেছে, তা record করুন:
docker inspect --format '{{.Config.Image}}' immich_server > /srv/immich/backup/immich-version.txtএ কাজের জন্য .env-এর ওপর নির্ভর করবেন না। Stock file-এ IMMICH_VERSION=v3 সেট করা থাকে। এটি একটি পরিবর্তনশীল tag, যা প্রতিটি 3.x release অনুসরণ করে। তাই কোন build আসলে dump লিখেছে, তা এটি জানায় না। .env-এও নির্দিষ্ট tag pin করুন।
সার্ভার থামিয়ে restic দিয়ে snapshot নিন
Immich চলার সময় UPLOAD_LOCATION-এর অধীন ফাইলগুলো অপরিবর্তনীয় থাকে না। সার্ভার নতুন upload লেখে, এবং storage template job ফাইলগুলো এক directory থেকে অন্য directory-তে সরায়। কোনো backup tool যদি লেখার মাঝপথে একটি ফাইল পড়ে, তাহলে সেটি ওই byte-গুলোকে পুরো ফাইল ধরে সংরক্ষণ করে; কোনো error-ও report হয় না। রান চলাকালীন সার্ভার container বন্ধ রাখুন:
docker stop immich_serverimmich_postgres চালু রাখুন, কারণ dump-এর জন্য এটি প্রয়োজন। সার্ভার আবার চালু না করা পর্যন্ত web interface এবং mobile app offline থাকবে। household instance-এ 03:00 সময়ে এটি সাধারণত সমস্যা নয়।
restic এখানে উপযুক্ত, কারণ ডেটা server ছাড়ার আগেই এটি deduplicate এবং encrypt করে। এটিকে এই সার্ভারে না থাকা একটি repository-তে নির্দেশ করুন:
export RESTIC_REPOSITORY=sftp:backup@backup.example.com:/srv/restic/immich
export RESTIC_PASSWORD_FILE=/root/.restic-password
restic initObject storage-ও একইভাবে কাজ করে। আপনি যদি সম্পূর্ণ copy নিজের hardware-এর বাইরে রাখতে চান, তাহলে এটিই ভালো সমাধান:
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 দ্বিতীয় মেশিনে আপনার পরিচালিত একটি MinIO bucket হতে পারে, অথবা যেকোনো S3-compatible provider হতে পারে। Library-র একই disk-এ থাকা repository আপনাকে ভুল করে delete করার ঘটনা থেকে সুরক্ষা দেয়, কিন্তু অন্য কোনো ঝুঁকি থেকে নয়।
এরপর snapshot নিন। এখানে শুধু প্রয়োজনীয় বিষয়গুলো তালিকাভুক্ত করা হয়েছে:
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 প্রতিবার সম্পূর্ণ tree পড়ে, কিন্তু আগে দেখা হয়নি এমন block-ই শুধু upload করে। তাই প্রথম snapshot-এ আপনার সম্পূর্ণ library স্থানান্তরিত হয়, আর পরের প্রতিটি snapshot-এ সেদিনের নতুন photo-গুলো স্থানান্তরিত হয়।
Retention এবং যে key-গুলো অন্যত্র রাখতে হবে
restic forget --prune --keep-daily 7 --keep-weekly 5 --keep-monthly 12forget index থেকে snapshot সরায়। --prune সেই data মুছে ফেলে, যার সর্বশেষ reference ছিল ওই snapshot-গুলো। --prune ছাড়া forget চালালে আপনার storage bill কখনো কমবে না।
Structure check সস্তা, তাই সপ্তাহে একবার চালান:
restic checkএটি repository metadata সামঞ্জস্যপূর্ণ কি না যাচাই করে। এটি আপনার data পড়ে না। মাসে একবার একটি sample আবার পড়ুন এবং recorded hash-এর সঙ্গে মিলিয়ে দেখুন:
restic check --read-data-subset=5%Storage backend-এ নীরব corruption শনাক্ত করতে এটিই একমাত্র check, কারণ এটি বাস্তব block download করে এবং তাদের checksum আবার গণনা করে। একটি photo library-তে সম্পূর্ণ --read-data চালালে পুরো repository download করতে হয়। Metered object storage-এ এর জন্য প্রকৃত খরচ হয়। তাই rolling subset-ই এমন সংস্করণ, যা বাস্তবে ব্যবহার করা হয়।
এখন সেই বিষয়টি, যা অনেকে এড়িয়ে যান। A restic repository password পুনরুদ্ধার করা যায় না। এর কোনো reset নেই এবং কোনো support ticket দিয়েও এটি ফেরত পাওয়া যায় না। আপনি যে server restore করতে চাইছেন, সেখানে যদি একমাত্র copy /root/.restic-password-এ থাকে, তাহলে আপনার backup encrypted noise-এ পরিণত হবে। Object storage access key এবং .env থেকে পাওয়া DB_PASSWORD-এর ক্ষেত্রেও একই কথা প্রযোজ্য। এগুলো এমন কোথাও রাখুন, যা এই machine চালু থাকার ওপর নির্ভর করে না: কাগজে ছাপিয়ে drawer-এ রাখুন, অথবা ভিন্ন hardware-এ চলা password manager-এ সংরক্ষণ করুন। সেই manager-টিও self-hosted হলে, তার ক্ষেত্রেও একই ব্যবস্থা নিতে হবে, এবং Vaultwarden-এর backup নেওয়া একটি আলাদা কাজ।
Immich পুনরুদ্ধারের কার্যকর ক্রম
পুনরুদ্ধারের ক্রম ঠিক না হলে ভালো backup থেকেও timeline খালি হতে পারে। নতুন host-এ এই ক্রম অনুসরণ করুন।
প্রথমে configuration ফিরিয়ে আনুন। এতে কোন version চালাতে হবে এবং path-গুলো কোথায় নির্দেশ করছে তা জানা যায়।
restic restore latest --target /restore \
--include /srv/immich/.env \
--include /srv/immich/docker-compose.yml \
--include /srv/immich/backupকোনো কিছু চালু হওয়ার আগে version নির্দিষ্ট করুন। immich-version.txt পড়ুন, .env-এ IMMICH_VERSION-কে ঠিক সেই tag-এ সেট করুন, এবং আপাতত সর্বশেষ release ব্যবহার করবেন না। Immich downgrade সমর্থন করে না, এমনকি patch release-এর মধ্যেও নয়। তাই নতুন server যদি পুরোনো dump-এর বিরুদ্ধে চালু হয়ে migration প্রয়োগ করে, তাহলে আগের অবস্থায় ফেরার কোনো উপায় থাকে না।
Media পুনরুদ্ধার করুন।
restic restore latest --target /restore --include /srv/immich/dataএরপর library, upload এবং profile সরিয়ে এই host-এ UPLOAD_LOCATION যে directory-র দিকে নির্দেশ করে, তার সরাসরি ভেতরে রাখুন। Host path পরিবর্তন করা যায়, কারণ compose file ওই directory-কে container-এর ভেতরের একটি নির্দিষ্ট path-এ bind করে। কিন্তু directory-র ভেতরের layout পরিবর্তন করা যাবে না।
Database আলাদাভাবে চালু করুন। DB_DATA_LOCATION খালি রাখুন, যাতে Postgres একটি নতুন cluster initialises করে।
cd /srv/immich
docker compose pull
docker compose create
docker start immich_postgres
docker exec immich_postgres pg_isready --username=postgresপ্রথমবারের setup শেষ হলে pg_isready accepting connections দেখায়। এতে কয়েক সেকেন্ড সময় লাগে। docker compose create সব container চালু না করেই build করে। এই ধাপের উদ্দেশ্য সেটিই: Immich server এখনো চালু করা যাবে না। খালি database-এর বিরুদ্ধে চালু হওয়া server migration প্রয়োগ করে, নতুন schema তৈরি করে এবং নতুন admin account তৈরি করতে বলে। তখন চলমান application-এর নিচে dump পুনরায় প্রয়োগ করতে হয়।
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এর দুটি অংশ গুরুত্বপূর্ণ কাজ করে। pg_dump তার output-এ নিরাপত্তার জন্য একটি খালি search_path লেখে, তাই sed রাখা হয়। এর ফলে dump-এর unqualified name কোনো অপ্রত্যাশিত schema-তে resolve করতে পারে না। Immich-এর vector-search type-গুলো public-এ থাকে। তাই search path খালি থাকলে restore vector type-সহ প্রথম column-এ পৌঁছে ERROR: type "vector" does not exist দিয়ে থেমে যায়। path-এ public যোগ করলে সমস্যাটি ঠিক হয়।
--single-transaction --set ON_ERROR_STOP=on পুরো restore-কে একটি transaction-এর মধ্যে চালায় এবং প্রথম error দেখা দিলে abort করে। ফলে হয় সম্পূর্ণ database পাওয়া যায়, নয়তো database অপরিবর্তিত থাকে। এটি না থাকলে মাঝপথে ব্যর্থতার পর এমন একটি database থেকে যায় যা চালু হয় এবং আপনার login গ্রহণ করে, কিন্তু অজানা সংখ্যক album অনুপস্থিত থাকে। আপনি বিষয়টি কয়েক সপ্তাহ পরে জানতে পারেন।
এখন সবকিছু চালু করুন।
docker compose up -d
docker compose ps
docker logs -f immich_serverImmich Server is listening on-এর মতো একটি startup line দেখা পর্যন্ত অপেক্ষা করুন। এরপর port 2283 খুলে পুরোনো credentials দিয়ে login করুন, কারণ user account-গুলো dump-এর সঙ্গে পুনরুদ্ধার হয়েছে। Login page যদি প্রথম admin account তৈরি করার প্রস্তাব দেয়, তাহলে database restore হয়নি। থামুন এবং psql-এর output আবার পড়ুন।
সরকারি restore নির্দেশনা সম্পর্কে একটি সতর্কতা আছে। সেগুলো docker compose down -v দিয়ে শুরু হয়। -v named volume মুছে দেয়। Stock compose file-এ UPLOAD_LOCATION এবং DB_DATA_LOCATION bind mount, তাই সেগুলো এই command-এর পরেও থাকে। আপনি যদি কোনো একটি named volume-এ পরিবর্তন করে থাকেন, তাহলে ওই command আপনার photo মুছে দেবে। command দেওয়ার আগে compose file পড়ে নিন।
Restore-এর পরে timeline খালি কেন
Timeline database row থেকে তৈরি হয়। Boot-এর সময় Immich upload/-এর ভেতর ঘুরে নতুন করে photo খুঁজে বের করে না, কারণ কোনো row না থাকলে কোনো file-এর owner, date বা album থাকে না। তাই সবচেয়ে সাধারণ ভুল restore হলো file ফিরেছে, কিন্তু database ফেরেনি। Immich চালু হয়ে একটি খালি schema তৈরি করে এবং আপনাকে এমন একটি কার্যকর instance দেয়, যার মধ্যে কোনো data নেই, যদিও disk আপনার photo-তে পূর্ণ। কিছুই হারায়নি। তবে কিছুই দৃশ্যমানও নয়। সমাধান হলো server বন্ধ রেখে, ঠিক আগের মতো dump পুনরায় প্রয়োগ করা।
দ্বিতীয় পরিস্থিতিটি কম স্পষ্ট। Database restore হয়, timeline entry দিয়ে পূর্ণ হয়, কিন্তু প্রতিটি asset খুলতে ব্যর্থ হয়। এর অর্থ row-গুলো এমন file-এর দিকে নির্দেশ করছে, যা container দেখতে পাচ্ছে না। সাধারণত library, upload এবং profile কোনো restic restore --target /restore-এর পরে এক স্তর বেশি গভীরে চলে যায়, কারণ কেউ সেটিকে সঠিক জায়গায় সরায়নি। অনুমান না করে container-এর ভেতর থেকে পরীক্ষা করুন:
docker exec immich_server ls /dataStock compose file UPLOAD_LOCATION-কে /data হিসেবে mount করে। তাই ওই listing-এ library, upload এবং profile দেখা উচিত। যদি একটি খালি directory বা ভুল জায়গায় থাকা srv folder দেখা যায়, তাহলে আপনার bind mount ভুল স্তরের দিকে নির্দেশ করছে এবং row-গুলো সঠিক আছে।
ব্যাকআপ ও restore-এর মধ্যে version মিল
Immich ঘন ঘন release প্রকাশ করে এবং এর সঙ্গে schema-ও পরিবর্তিত হয়। তাই একটি dump যে server এটি লিখেছে, সেই server-এর schema বহন করে।
পুরোনো dump নতুন server-এ restore করলে সাধারণত কাজ করে। কারণ server start হওয়ার সময় pending migration প্রয়োগ করে এবং schema-কে ধাপে ধাপে নতুন অবস্থায় নিয়ে যায়। এই পথটি release sequence অনুযায়ী পরীক্ষা করা হয়। এক ধাপে একাধিক major version পার হলে সমস্যা হয়। Project major release-গুলোতে breaking change রাখে এবং changelog-এ সেগুলো নথিভুক্ত করে।
নতুন dump পুরোনো server-এ restore করলে একেবারেই কাজ করে না। Dump-এ এমন table ও column থাকে, যেগুলো পুরোনো code চেনে না। Immich জানায় যে patch release-এর মধ্যেও downgrade সমর্থিত নয়। ব্যবহার করার মতো কোনো rollback command নেই।
তাই নিরাপদ restore পদ্ধতিটি সরল। যে exact version dump লিখেছিল, সেই version চালান। Dump replay করুন। লগ ইন করে timeline সম্পূর্ণ আছে কি না নিশ্চিত করুন। তারপর upgrade করুন। একবারে একটি release upgrade করুন। প্রতিটি upgrade-এর পরে IMMICH_VERSION পরিবর্তন করুন এবং docker compose pull && docker compose up -d চালান। এখানে এক সপ্তাহের dump সংরক্ষণ করাও সহায়ক। সর্বশেষ dump যদি ব্যর্থ upgrade চলাকালীন তৈরি হয়ে থাকে, তাহলে আগের দিনের dump এখনও repository-তে থাকবে।
প্রতি মাসে ব্যাকআপ যাচাই করুন
যে ব্যাকআপ কখনও restore করা হয়নি, সেটি কেবল একটি অনুমান। মাসে একবার সেটি একটি সাময়িক instance-এ restore করে একটি ছবি খুলে দেখুন। এই অনুশীলনে প্রায় বিশ মিনিট লাগে। এই কাজটিই এই পৃষ্ঠার বাকি অংশকে একটি recovery plan-এ পরিণত করে।
restic snapshots
restic stats latestsnapshots-এ গত রাতের run তালিকাভুক্ত থাকা উচিত। stats latest-এ আপনার library-র কাছাকাছি আকার দেখানো উচিত, কয়েক megabyte নয়।
একটি scratch directory-তে restore করুন। সম্ভব হলে spare host ব্যবহার করুন:
restic restore latest --target /tmp/immich-drillRestored set থেকে docker-compose.yml এবং .env copy করে বাইরে আনুন। এরপর copy-তে তিনটি পরিবর্তন করুন। UPLOAD_LOCATION এবং DB_DATA_LOCATION-কে /tmp/immich-drill-এর অধীনে থাকা directory-তে নির্দেশ করুন। Web port অন্য কোথাও publish করুন: 12283:2283, 2283:2283-এর পরিবর্তে। container_name:-এর line-গুলো মুছে দিন। কারণ stock compose file-এ immich_server-এর মতো নাম hard-code করা থাকে। ফলে একই host-এ দ্বিতীয় stack প্রথমটির সঙ্গে সংঘর্ষে জড়ায় এবং Docker সেটি তৈরি করতে অস্বীকার করে।
উপরের restore sequence চালান: শুধু database restore করুন, dump replay করুন, তারপর docker compose up -d। এবার চারটি যাচাই করুন। এগুলো সফল হলে restore কার্যকর প্রমাণিত হবে।
- অনুশীলনের আগে যে password ব্যবহার করতেন, সেটি দিয়ে login করুন। Account কাজ করলে dump restore হয়েছে।
- Timeline খুলে সবচেয়ে পুরোনো মাসে scroll করুন। সম্পূর্ণ date range জুড়ে asset থাকলে বোঝা যাবে সব row ফিরে এসেছে, শুধু সাম্প্রতিকগুলো নয়।
- একটি ছবি full size-এ খুলে original download করুন।
sha256sumব্যবহার করে সেটিকে আপনার live library-র একই file-এর সঙ্গে তুলনা করুন। Hash মিলে গেলে বোঝা যাবে restic-এর মাধ্যমে সম্পূর্ণ প্রক্রিয়ায় file-এর bytes অক্ষত ছিল।
এরপর drill directory-তে docker compose down -v চালিয়ে অনুশীলনের environment সরিয়ে ফেলুন এবং /tmp/immich-drill মুছে দিন। তারিখটি এমন কোথাও লিখে রাখুন যেখানে আপনি দেখতে পাবেন। কারণ এই কাজের সম্পূর্ণ মূল্য পরের মাসে আবার এটি করার মধ্যে। আপনি যদি এখনও কোন photo server ব্যবহার করবেন তা নির্ধারণ করে থাকেন, PhotoPrism এবং Immich-এর তুলনা-এ এই বিষয়েই দুটির পার্থক্য ব্যাখ্যা করা হয়েছে।
FAQ
আমাকে কি backup নেওয়ার জন্য Immich বন্ধ করতে হবে?
immich_server বন্ধ রাখুন এবং immich_postgres চালু রাখুন। Database থামানোর প্রয়োজন নেই, কারণ pg_dump একটি MVCC snapshot-এর মধ্যে পড়ে এবং অন্য কোনো process লিখলেও একই consistent মুহূর্তের অবস্থা দেখে। Files বন্ধ করার কারণ হলো server নতুন upload লেখে এবং storage template job files-কে এক directory থেকে অন্য directory-তে সরায়। তাই backup tool কোনো file লেখার মাঝপথে পড়ে error ছাড়াই truncated copy সংরক্ষণ করতে পারে। Snapshot নেওয়ার আগে docker stop immich_server এবং পরে docker start immich_server চালালে এই race condition দূর হয়।
pg_dump চালানোর পরিবর্তে কি Postgres data folder কপি করতে পারি?
না। Live data directory rolling copy করলে বিভিন্ন file বিভিন্ন সময়ে পড়া হয়। ফলে ফলাফলটি কোনো একক consistent state হয় না। Postgres startup-এর সময় PANIC: could not locate a valid checkpoint record দিয়ে এটি প্রত্যাখ্যান করতে পারে, অথবা পরে damaged page-এর কারণে ব্যর্থ হতে পারে। সবকিছু বন্ধ রেখে নেওয়া copy-ও নির্দিষ্ট database build-এর সঙ্গে আবদ্ধ থাকে। Immich নির্দিষ্ট vector-search extension version-সহ Postgres 14 image নির্ধারণ করে, এবং অন্য কোনো পরিবেশে directory-টি খোলা যাবে না। SQL dump plain text হিসেবে থাকে এবং যেকোনো compatible server-এ replay করা যায়।
Restore করার পরে আমার Immich timeline খালি কেন?
কারণ timeline database row থেকে তৈরি হয়, আর আপনি database ছাড়া files restore করেছেন। Immich photos পুনরায় খুঁজে বের করার জন্য কখনো upload/ scan করে না। তাই কোনো row না থাকা files অদৃশ্য থাকে। Photos নিজেরা অক্ষত থাকে। Server বন্ধ করুন, freshly initialised Postgres-এ dump replay করুন, তারপর stack চালু করুন। বিপরীতে timeline পূর্ণ থাকলেও প্রতিটি photo খোলা ব্যর্থ হলে সমস্যা অন্যদিকে: library, upload এবং profile container-এর ভিতরে bind করা directory-র সরাসরি অংশ নয়। docker exec immich_server ls /data দিয়ে এটি পরীক্ষা করুন।
Backup-এ Immich-এর কোন folder বাদ দিতে পারি?
thumbs এবং encoded-video originals থেকে পুনরায় তৈরি হয়, আর DB_DATA_LOCATION dump থেকে পুনর্নির্মাণ করা যায়। তাই backup set-এ এগুলোর কোনোটি রাখার প্রয়োজন নেই। এগুলো বাদ দিলে storage-এর পরিবর্তে restore-এর পরে সময় ব্যয় হবে। কারণ বড় library-এর previews এবং transcodes পুনর্নির্মাণে কয়েক ঘণ্টা CPU সময় লাগতে পারে। এই কাজ Administration > Jobs থেকে missing assets-এর জন্য চালানো হয়। কখনো বাদ দেওয়া যাবে না library, upload এবং profile-কে, কারণ প্রতিটি original-এর একমাত্র copy এগুলোর মধ্যেই থাকে।
নতুন version-এ কি Immich dump restore করতে পারি?
সাধারণত পারেন, কারণ server startup-এর সময় pending migration প্রয়োগ করে এবং schema-কে ধাপে ধাপে পরবর্তী অবস্থায় নিয়ে যায়। বিপরীতটি ব্যর্থ হয়। Immich downgrade সমর্থন করে না, এমনকি patch release-এর মধ্যেও নয়। তাই নতুন release থেকে নেওয়া dump পুরোনো server-এ load করা যাবে না। IMMICH_VERSION-কে dump লেখার release-এ pinned রেখে restore করুন, timeline সম্পূর্ণ আছে কি না নিশ্চিত করুন, তারপর upgrade করুন। প্রতিটি dump-এর পাশে docker inspect --format '{{.Config.Image}}' immich_server দিয়ে version লিখে রাখুন। কারণ default IMMICH_VERSION=v3 একটি floating tag, যা কোনো নির্দিষ্ট তথ্য দেয় না।