SSD Nodes Learn Hosting plans →
تعلیمی Matt Connorتحریر: Matt Connor · اپ ڈیٹ شدہ 2026-08-13

Immich کا backup اور restore: VPS پر درست طریقہ

Immich backup میں اصل files، Postgres SQL dump اور stack files شامل کریں۔ data directory copy کرنا backup نہیں، اور غلط restore ترتیب timeline خالی کر دیتی ہے۔

Immich کے backup میں کیا شامل ہونا چاہیے

Immich کا backup ایک ہی وقت میں محفوظ کی گئی 3 چیزوں پر مشتمل ہوتا ہے۔ UPLOAD_LOCATION کے تحت موجود اصل فائلیں۔ Postgres database کا SQL dump۔ وہ .env اور docker-compose.yml جو stack کی وضاحت کرتے ہیں۔ بحالی کے لیے Immich server بند ہونے کی حالت میں اس dump کو نئی database میں دوبارہ شامل کریں، اور اس کے بعد ہی stack کی باقی services شروع کریں۔ اگر ترتیب غلط ہو جائے تو مکمل disk کے اوپر چلتا ہوا Immich ملے گا، لیکن اس کی timeline خالی ہوگی۔

یہ تقسیم اس لیے اہم ہے کہ Immich اپنی state کو 2 ایسی جگہوں پر رکھتا ہے جو ایک دوسرے سے لاعلم ہیں۔ Postgres میں ہر album، ہر face cluster، ہر shared link، ہر user account اور API key، اور ہر asset کا محفوظ شدہ path موجود ہوتا ہے۔ Filesystem میں تصاویر کے اصل pixels ہوتے ہیں۔ Database کے بغیر files بحال کرنے سے Immich میں کچھ بھی نظر نہیں آئے گا۔ Files کے بغیر database بحال کرنے سے ہر asset کھولنے پر broken image دکھائی دے گی۔

یہاں دیے گئے commands Immich v3.1.0 کے لیے ہیں، جو August 2026 کے آغاز میں موجودہ release تھا۔ Project تیزی سے releases جاری کرتا ہے، اور documented backup procedure ایک سے زیادہ مرتبہ تبدیل ہو چکا ہے، اس لیے کچھ بھی copy کرنے سے پہلے اپنے زیرِ استعمال version کی تصدیق کریں۔ اگر stack ابھی up نہیں ہے تو Immich installation guide سے شروع کریں اور پھر یہاں واپس آئیں۔

اپنے paths کے مطلوبہ مقامات کو سمجھیں

.env میں موجود دو variables اس پورے صفحے کے نتائج طے کرتے ہیں۔ UPLOAD_LOCATION وہ parent directory ہے جس میں Immich تمام media لکھتا ہے۔ DB_DATA_LOCATION، Postgres کی data directory ہے۔

stock example.env، UPLOAD_LOCATION=./library مقرر کرتی ہے، جو ایک الجھن پیدا کرنے والی default setting ہے، کیونکہ Immich پھر اسی کے اندر library نامی folder بناتا ہے۔ آپ کی اصل فائلیں ./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.0

UPLOAD_LOCATION کے اندر Immich کئی folders بناتا ہے۔ ان میں سے تین میں ایسا data ہوتا ہے جسے کوئی job دوبارہ نہیں بنا سکتی:

  • library: اصل فائلیں، آپ کے storage template کے مطابق ترتیب دی گئی
  • upload: وہ اصل فائلیں جو ابھی template layout میں منتقل نہیں ہوئی ہیں، اور زیرِ تکمیل uploads
  • profile: صارف کی profile pictures

اگر library ضائع ہو جائے تو photo بھی ضائع ہو جاتی ہے۔ Immich اصل فائل کی دوسری copy کہیں محفوظ نہیں رکھتا۔

Postgres ڈیٹا ڈائریکٹری کی نقل بیک اپ کیوں نہیں ہوتی

DB_DATA_LOCATION بظاہر آسان ہدف ہے۔ یہ ایک ڈائریکٹری ہے، rsync اسے copy کر دے گا، اور copy بغیر کسی error کے مکمل ہو جاتی ہے۔ پھر بھی یہ بیک اپ نہیں ہے۔ اس کی دو وجوہات ہیں، اور دونوں کی ناکامی آپ دیکھ سکتے ہیں۔

پہلی وجہ tearing ہے۔ Postgres ہر تبدیلی پہلے write-ahead log (WAL) میں لکھتا ہے، پھر checkpoint کے وقت اسے table files پر لاگو کرتا ہے۔ اس لیے کسی بھی لمحے disk پر موجود files عارضی حالت میں ہوتی ہیں۔ چار منٹ لینے والی rolling copy پہلی file 02:00 پر اور آخری file 02:04 پر پڑھتی ہے۔ یہ دونوں files ایک ہی transaction سے متعلق نہیں ہوتیں۔ جب آپ نتیجے پر Postgres شروع کرتے ہیں تو یا تو وہ startup کے وقت PANIC: could not locate a valid checkpoint record کے ساتھ انکار کر دیتا ہے، یا شروع ہونے کے بعد خراب page کو پہلی بار پڑھتے ہی invalid page in block 1234 of relation base/16384/... کے ساتھ بند ہو جاتا ہے۔ اس copy سے دونوں صورتوں میں recovery ممکن نہیں ہوتی۔

دوسری وجہ اس وقت بھی برقرار رہتی ہے جب آپ پہلے سب کچھ روک دیں۔ Postgres کی data directory ان عین binaries سے وابستہ ہوتی ہے جنہوں نے اسے لکھا تھا۔ Immich اپنی database image کو digest کے ذریعے pin کرتا ہے؛ فی الحال یہ ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0 ہے۔ یہ Postgres 14 ہے، جس میں vector-search کی دو extensions compiled ہیں۔ اس build سے لکھی گئی data directory مختلف Postgres major version کے تحت نہیں کھلے گی، اور نہ ہی مختلف extension versions والی build کے تحت کھلے گی۔ آپ کے restore host کو image بالکل اسی طرح دوبارہ فراہم کرنی ہوگی۔ SQL dump کو اس کی پروا نہیں ہوتی۔ یہ text ہوتا ہے، اور کوئی بھی compatible server اسے دوبارہ چلا سکتا ہے۔

pg_dump tearing کے مسئلے کو براہ راست ختم کرتا ہے۔ یہ پوری database کو ایک ہی MVCC (multi-version concurrency control) snapshot کے اندر پڑھتا ہے۔ اس طرح دیگر writes جاری رہنے کے باوجود اسے database بالکل اسی حالت میں نظر آتی ہے جیسی ایک خاص لمحے میں تھی۔ اسی لیے database dump لینے کے لیے Postgres کو روکنا ضروری نہیں ہوتا۔

بیک اپ میں کن چیزوں کو شامل نہ کیا جا سکتا ہے

یہ چیزیں دوبارہ تیار ہو جاتی ہیں، اس لیے آپ انہیں چھوڑ سکتے ہیں:

  • thumbs: preview اور thumbnail تصاویر
  • encoded-video: transcoded ویڈیو
  • DB_DATA_LOCATION: dump سے دوبارہ تیار ہونے والی فائلیں
  • model-cache Docker volume: machine learning models، جو ضرورت کے وقت دوبارہ download ہو جاتے ہیں

انہیں چھوڑنا ایک سمجھوتا ہے، مفت فائدہ نہیں۔ بڑے library کے لیے thumbnails اور transcodes دوبارہ تیار کرنے میں چھوٹے VPS پر کئی گھنٹے CPU وقت لگ سکتا ہے، اور اس دوران timeline میں مسلسل سرمئی placeholders دکھائی دیتے ہیں۔ انہیں Administration > Jobs سے دوبارہ چلائیں، اور "Generate Thumbnails" اور "Transcode Videos" کو missing assets پر چلنے کے لیے set کریں۔ اگر آپ کے backup target میں جگہ موجود ہے تو انہیں شامل کریں اور انتظار سے بچیں۔ اگر آپ storage limit کے قریب ہیں تو انہیں چھوڑ دیں اور rebuild کے لیے منصوبہ بنائیں۔ Immich library کا سائز طے کرنا میں بتایا گیا ہے کہ یہ folders originals کے مقابلے میں کتنے بڑے ہو سکتے ہیں۔

ایک اور folder کے بارے میں جاننا مفید ہے۔ UPLOAD_LOCATION/backups میں Immich کے اپنے automatic database dumps محفوظ ہوتے ہیں۔ یہ روزانہ 02:00 پر لکھے جاتے ہیں، آخری 14 dumps رکھے جاتے ہیں، اور ان کی configuration Administration > Settings > Backup کے تحت کی جا سکتی ہے۔ ان پر آپ کی کوئی اضافی لاگت نہیں آتی اور یہ واقعی مفید ہوتے ہیں۔ تاہم یہ اسی disk پر موجود ہوتے ہیں جس پر وہ library محفوظ ہوتی ہے جس کا یہ تحفظ کرتے ہیں۔ اس لیے یہ خراب migration کی صورت میں مدد دیتے ہیں، dead server کی صورت میں نہیں۔ اپنا dump پھر بھی بنائیں، کیونکہ آپ کے ہاتھ سے trigger کیا گیا 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 ایسی database میں دوبارہ چلتا ہے جس میں پہلے ہی objects موجود ہوں، اور پہلے object پر رکنے کے بجائے عمل جاری رہتا ہے۔

اب اس تفصیل کو دیکھیں جو backup scripts کو خاموشی سے ناکام بنا دیتی ہے۔ یہ command ایک pipeline ہے، اور shell pipeline میں آخری command کا exit status رپورٹ کرتا ہے۔ اگر pg_dump ناکام ہو جائے، خواہ غلط password کی وجہ سے یا اس لیے کہ container چل نہیں رہا، تو gzip کو خالی stream ملتی ہے، وہ بظاہر درست gzip file لکھتا ہے، اور 0 کے ساتھ ختم ہو جاتا ہے۔ آپ کی script کامیابی 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 کی پہلی سطر -- PostgreSQL database dump ہوتی ہے۔ چند سو bytes کی file ناکام dump ہے، چاہے script نے کچھ بھی بتایا ہو۔

اس dump کے ساتھ یہ بھی درج کریں کہ اسے کس build نے لکھا تھا:

docker inspect --format '{{.Config.Image}}' immich_server > /srv/immich/backup/immich-version.txt

اس مقصد کے لیے .env پر انحصار نہ کریں۔ stock file میں IMMICH_VERSION=v3 مقرر ہوتا ہے، جو ہر 3.x release کے ساتھ تبدیل ہونے والا tag ہے؛ اس لیے یہ نہیں بتاتا کہ dump اصل میں کس build نے لکھا تھا۔ .env میں بھی exact tag مقرر کریں۔

سرور کو روکیں، پھر restic سے snapshot بنائیں

UPLOAD_LOCATION کے تحت فائلیں Immich کے چلنے کے دوران immutable نہیں رہتیں۔ سرور نئی uploads لکھتا ہے، اور storage template job فائلوں کو ایک directory سے دوسری directory میں منتقل کرتی ہے۔ اگر backup tool کسی فائل کو لکھے جانے کے دوران درمیان سے پڑھ لے تو وہ ان bytes کو پوری فائل سمجھ کر محفوظ کر لیتا ہے، اور کوئی error رپورٹ نہیں ہوتا۔ run کے دورانیے تک سرور container روک دیں:

docker stop immich_server

immich_postgres کو چلتا رہنے دیں، کیونکہ dump کے لیے اسے درکار ہے۔ سرور دوبارہ start ہونے تک web interface اور mobile app offline رہیں گے۔ household instance پر 03:00 بجے یہ عموماً قابل قبول ہوتا ہے۔

restic یہاں موزوں ہے، کیونکہ یہ data کو server سے باہر بھیجنے سے پہلے deduplicate اور encrypt کرتا ہے۔ اسے ایسے repository کی طرف point کریں جو اس server پر موجود نہ ہو:

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

Object 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 دوسرے machine پر آپ کے زیر انتظام 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_server

restic ہر run میں پوری tree پڑھتا ہے، لیکن صرف وہ blocks upload کرتا ہے جو پہلے نہیں دیکھے گئے۔ اس لیے پہلا snapshot پوری library منتقل کرتا ہے، جبکہ اس کے بعد ہر snapshot صرف دن کی نئی photos منتقل کرتا ہے۔

Retention اور وہ keys جو کہیں اور محفوظ ہونی چاہییں

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

forget index سے snapshots ہٹا دیتا ہے۔ --prune وہ حصہ ہے جو اس data کو حذف کرتا ہے جس کے لیے وہ snapshots آخری reference تھے۔ --prune کے بغیر forget چلانے سے آپ کا storage bill کبھی کم نہیں ہوگا۔

Structure checks سستے ہوتے ہیں، اس لیے انہیں ہفتے میں ایک بار چلائیں:

restic check

اس سے تصدیق ہوتی ہے کہ repository metadata consistent ہے۔ یہ آپ کے data کو نہیں پڑھتا۔ مہینے میں ایک بار sample کو دوبارہ پڑھیں اور اسے recorded hashes کے خلاف check کریں:

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

یہی واحد check ہے جو storage backend پر ہونے والی silent corruption کو پکڑتا ہے، کیونکہ یہ حقیقی blocks download کرکے ان کے checksums دوبارہ calculate کرتا ہے۔ Photo library پر مکمل --read-data چلانے کا مطلب پورا repository download کرنا ہے۔ Metered object storage پر اس کی حقیقی لاگت آتی ہے، اس لیے rolling subset وہ طریقہ ہے جسے لوگ عملی طور پر استعمال کرتے ہیں۔

اب اس حصے کی بات کرتے ہیں جسے لوگ چھوڑ دیتے ہیں۔ A restic repository password recover نہیں کیا جا سکتا۔ اس کے لیے reset موجود نہیں، اور support ticket بھی مدد نہیں دے گی۔ اگر اس password کی واحد copy /root/.restic-password میں اسی server پر موجود ہے جسے آپ restore کرنے کی کوشش کر رہے ہیں، تو آپ کے backups encrypted noise ہیں۔ یہی بات object storage access key اور .env سے حاصل ہونے والے DB_PASSWORD پر بھی لاگو ہوتی ہے۔ ان سب کو ایسی جگہ محفوظ رکھیں جس کا انحصار اس machine کے زندہ ہونے پر نہ ہو: انہیں print کرکے drawer میں رکھیں، یا مختلف hardware پر چلنے والے password manager میں محفوظ کریں۔ اگر وہ manager بھی self-hosted ہے تو اسے بھی اسی طرح محفوظ کرنا ہوگا، اور Vaultwarden کا backup لینا الگ کام ہے۔

Immich کو درست ترتیب سے بحال کریں

بحالی کی ترتیب ہی یہ طے کرتی ہے کہ اچھے backups کے باوجود timeline خالی کیوں رہتی ہے۔ نئے host پر یہ sequence فالو کریں۔

سب سے پہلے config واپس لائیں۔ اس سے معلوم ہوتا ہے کہ کون سا version چلانا ہے اور paths کہاں point کرتے ہیں۔

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

کسی بھی چیز کے شروع ہونے سے پہلے version کو pin کریں۔ immich-version.txt پڑھیں، .env میں IMMICH_VERSION کو اسی exact tag پر set کریں، اور فی الحال جدید ترین release استعمال نہ کریں۔ Immich downgrading کو support نہیں کرتا، حتیٰ کہ patch releases کے درمیان بھی نہیں۔ اس لیے اگر نیا server پرانے dump کے خلاف شروع ہو کر اپنی migrations چلا دے تو واپسی کا کوئی راستہ نہیں رہتا۔

media بحال کریں۔

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

اس کے بعد library، upload اور profile کو اس طرح منتقل کریں کہ وہ اس host پر UPLOAD_LOCATION جس directory کی طرف point کرتا ہے، اسی کے اندر براہِ راست موجود ہوں۔ Host path تبدیل ہو سکتا ہے، کیونکہ compose file اس directory کو container کے اندر ایک fixed path سے bind کرتی ہے۔ اس کے اندر کا layout تبدیل نہیں ہو سکتا۔

database کو الگ سے شروع کریں۔ DB_DATA_LOCATION کو خالی رہنے دیں تاکہ Postgres ایک تازہ cluster initialise کرے۔

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 print کرتا ہے۔ اس میں چند seconds لگتے ہیں۔ docker compose create ہر container کو start کیے بغیر build کرتا ہے، اور اسی step کا مقصد یہی ہے: Immich server ابھی نہیں چلنا چاہیے۔ جو server empty database کے خلاف شروع ہوتا ہے، وہ اپنی migrations چلاتا ہے، نیا schema بناتا ہے اور آپ سے نیا admin account بنانے کو کہتا ہے۔ اس کے بعد آپ چلتی ہوئی application کے نیچے dump دوبارہ restore کر رہے ہوتے ہیں۔

dump replay کریں۔

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

اس کے دو حصے حقیقی کام انجام دیتے ہیں۔ sed اس لیے موجود ہے کہ pg_dump حفاظتی اقدام کے طور پر اپنے output میں ایک empty search_path لکھتا ہے، تاکہ dump میں موجود غیر مخصوص names کسی unexpected schema سے resolve نہ ہوں۔ Immich کے vector-search types public میں موجود ہیں۔ اس لیے empty search path کے ساتھ restore پہلے ایسے column تک پہنچتے ہی رک جاتا ہے جس میں vector type declared ہو، اور psql ERROR: type "vector" does not exist کے ساتھ بند ہو جاتا ہے۔ public کو path پر واپس رکھنے سے یہ مسئلہ حل ہو جاتا ہے۔

--single-transaction --set ON_ERROR_STOP=on پورے restore کو ایک transaction میں wrap کرتا ہے جو پہلی error پر abort ہو جاتا ہے۔ آپ کو یا تو مکمل database ملتا ہے یا database میں کوئی تبدیلی نہیں ہوتی۔ اس کے بغیر درمیان میں failure ایسا database چھوڑ دیتا ہے جو start ہوتا ہے، آپ کا login قبول کرتا ہے، لیکن نامعلوم تعداد میں albums سے محروم ہوتا ہے۔ آپ کو یہ کمی کئی ہفتوں بعد معلوم ہوتی ہے۔

اب سب کچھ شروع کریں۔

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

Immich Server is listening on جیسی startup line کا انتظار کریں۔ پھر port 2283 کھولیں اور اپنی پرانی credentials سے login کریں، کیونکہ user accounts dump کے ساتھ واپس آ گئے ہیں۔ اگر login page اس کے بجائے پہلا admin account بنانے کی پیشکش کرے تو database restore نہیں ہوا۔ رک جائیں اور psql output دوبارہ پڑھیں۔

official restore instructions کے بارے میں ایک انتباہ، جو docker compose down -v سے شروع ہوتی ہیں۔ -v named volumes remove کرتا ہے۔ stock compose file میں UPLOAD_LOCATION اور DB_DATA_LOCATION bind mounts ہیں، اس لیے وہ اس command کے بعد برقرار رہتے ہیں۔ اگر آپ نے ان میں سے کسی کو named volume میں تبدیل کیا ہے تو وہ command آپ کی photos delete کر دے گی۔ اسے type کرنے سے پہلے اپنی compose file پڑھیں۔

بحالی کے بعد timeline خالی کیوں ہے

timeline database rows سے تیار ہوتی ہے۔ Immich boot کے وقت upload/ میں دوبارہ photos تلاش نہیں کرتا، کیونکہ جس file کے لیے کوئی row نہ ہو اس کا کوئی owner، date یا album نہیں ہوتا۔ اس لیے سب سے عام ناقص restore یہ ہے کہ files واپس آ جاتی ہیں، لیکن database موجود نہیں ہوتا۔ Immich start ہوتا ہے، empty schema بناتا ہے، اور آپ کو ایک working instance فراہم کرتا ہے جس میں کچھ نہیں ہوتا، جبکہ disk آپ کی photos سے بھری ہوتی ہے۔ کچھ بھی ضائع نہیں ہوتا۔ لیکن کچھ بھی دکھائی بھی نہیں دیتا۔ اس کا حل یہ ہے کہ server stopped حالت میں dump کو، بالکل اوپر بیان کیے گئے طریقے کے مطابق، دوبارہ apply کریں۔

دوسری صورت زیادہ خاموش ہوتی ہے۔ database restore ہو جاتا ہے، timeline entries سے بھر جاتی ہے، لیکن ہر asset open ہونے میں ناکام رہتا ہے۔ اس کا مطلب ہے کہ rows ان files کی طرف اشارہ کر رہی ہیں جنہیں container دیکھ نہیں سکتا۔ عموماً ایسا اس لیے ہوتا ہے کہ library، upload اور profile کسی restic restore --target /restore کے بعد ایک level زیادہ اندر موجود ہیں، جسے کسی نے درست جگہ منتقل نہیں کیا۔ اندازہ لگانے کے بجائے container کے اندر سے چیک کریں:

docker exec immich_server ls /data

stock compose file، UPLOAD_LOCATION کو /data پر mount کرتی ہے، اس لیے اس listing میں library، upload اور profile دکھائی دینے چاہییں۔ اگر empty directory یا بے محل srv folder دکھائی دے تو آپ کا bind mount غلط level کی طرف اشارہ کر رہا ہے، جبکہ rows درست ہیں۔

بیک اپ اور بحالی کے ورژن کا مطابقت

Immich کے نئے releases کثرت سے آتے ہیں، اور schema بھی ان کے ساتھ تبدیل ہوتا ہے۔ اس لیے dump میں وہی schema شامل ہوتا ہے جو اسے لکھنے والے server پر موجود تھا۔

پرانے dump کو عموماً نئے server میں restore کیا جا سکتا ہے، کیونکہ server شروع ہوتے وقت زیرِ التوا migrations لاگو کرتا ہے اور schema کو مرحلہ وار آگے بڑھاتا ہے۔ اس راستے کی جانچ release sequence کے مطابق کی جاتی ہے۔ ایک ہی مرحلے میں کئی major versions کو عبور کرنے پر مسائل پیدا ہوتے ہیں۔ project breaking changes کو major releases تک محدود رکھتا ہے اور انہیں اپنے changelog میں درج کرتا ہے۔

نئے dump کو پرانے server میں restore کرنا بالکل کام نہیں کرتا۔ dump میں ایسی tables اور columns شامل ہوتے ہیں جن سے پرانا code واقف نہیں ہوتا۔ Immich کے مطابق downgrade کرنا patch releases کے درمیان بھی unsupported ہے۔ اس کے لیے کوئی rollback command دستیاب نہیں۔

اس لیے محفوظ restore کا طریقہ سادہ ہے۔ وہی exact version چلائیں جس نے dump لکھا تھا، dump کو replay کریں، login کریں، timeline کے مکمل ہونے کی تصدیق کریں، اور اس کے بعد ہی upgrade کریں۔ ہر بار ایک release upgrade کریں، IMMICH_VERSION میں اضافہ کریں، اور ہر upgrade کے بعد docker compose pull && docker compose up -d چلائیں۔ ایک ہفتے کے dumps محفوظ رکھنا یہاں بھی مفید ہے۔ اگر معلوم ہو کہ تازہ ترین dump ناکام upgrade کے دوران بنایا گیا تھا، تو کل کا dump repository میں موجود رہے گا۔

ہر ماہ بیک اپ کی تصدیق کریں

جس بیک اپ کو آپ نے کبھی restore نہیں کیا، وہ صرف ایک اندازہ ہے۔ ماہ میں ایک بار اسے عارضی instance میں restore کریں اور ایک تصویر دیکھیں۔ یہ مشق تقریباً بیس منٹ لیتی ہے، اور یہی وہ واحد عمل ہے جو اس پورے صفحے کو recovery plan میں تبدیل کرتا ہے۔

restic snapshots
restic stats latest

snapshots میں گزشتہ رات کا run درج ہونا چاہیے۔ stats latest میں library کے قریب size رپورٹ ہونی چاہیے، چند megabytes نہیں۔

Restore کو scratch directory میں کریں، بہتر ہے کہ spare host استعمال کریں:

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

Restored set سے docker-compose.yml اور .env copy کریں، پھر copy میں تین چیزیں تبدیل کریں۔ UPLOAD_LOCATION اور DB_DATA_LOCATION کو /tmp/immich-drill کے اندر موجود directories کی طرف point کریں۔ Web port کو کسی دوسرے مقام پر publish کریں: 12283:2283 کو 2283:2283 کے بجائے استعمال کریں۔ container_name: والی lines حذف کریں، کیونکہ stock compose file immich_server جیسے names hard-code کرتی ہے۔ اس لیے اسی host پر دوسرا stack پہلے stack سے ٹکرا جاتا ہے اور Docker اسے create کرنے سے انکار کر دیتا ہے۔

اوپر دیا گیا restore sequence چلائیں: پہلے صرف database، پھر dump replay کریں، اور اس کے بعد docker compose up -d چلائیں۔ اب وہ چار checks کریں جو واقعی ثابت کرتی ہیں کہ restore درست ہوا ہے۔

  1. اس password سے login کریں جو آپ نے drill سے پہلے استعمال کیا تھا۔ اگر account کام کرے تو dump restore ہو چکا ہے۔
  2. Timeline کھولیں اور قدیم ترین ماہ تک scroll کریں۔ پوری date range میں assets موجود ہوں تو اس کا مطلب ہے کہ تمام rows واپس آ گئی ہیں، صرف حالیہ rows نہیں۔
  3. ایک تصویر full size میں کھولیں اور original download کریں۔
  4. اسے اپنی live library میں موجود اسی file سے sha256sum کے ذریعے compare کریں۔ Matching hashes کا مطلب ہے کہ restic کے ذریعے ہونے والے round trip میں bytes محفوظ رہے۔

اس کے بعد drill directory میں docker compose down -v چلا کر drill ختم کریں اور /tmp/immich-drill حذف کریں۔ تاریخ ایسی جگہ لکھیں جہاں آپ اسے دیکھ سکیں، کیونکہ اس عمل کی اصل افادیت اسی میں ہے کہ آپ اسے اگلے ماہ دوبارہ کریں۔ اگر آپ اب بھی یہ فیصلہ کر رہے ہیں کہ کس photo server کو مستقل طور پر استعمال کرنا ہے تو PhotoPrism اور Immich کا تقابلی جائزہ میں بتایا گیا ہے کہ اس مخصوص معاملے میں دونوں میں کیا فرق ہے۔

FAQ

کیا مجھے بیک اپ لینے کے لیے Immich روکنا ہوگا؟

immich_server کو روک دیں اور immich_postgres کو چلتا رہنے دیں۔ Database کو روکنے کی ضرورت نہیں، کیونکہ pg_dump ایک MVCC snapshot کے اندر سے read کرتا ہے اور باقی کسی بھی write کے جاری ہونے کے باوجود ایک ہی consistent لمحہ دیکھتا ہے۔ Files کو روکنے کی ضرورت ہوتی ہے: server نئی uploads لکھتا ہے اور storage template job files کو directories کے درمیان منتقل کرتا ہے، اس لیے backup tool کسی file کو write کے دوران آدھا پڑھ کر بغیر کسی error کے truncated copy محفوظ کر سکتا ہے۔ Snapshot سے پہلے docker stop immich_server اور اس کے بعد docker start immich_server چلانے سے یہ race ختم ہو جاتی ہے۔

کیا میں pg_dump چلانے کے بجائے Postgres data folder copy کر سکتا ہوں؟

نہیں۔ Live data directory کی rolling copy مختلف files کو مختلف لمحوں میں read کرتی ہے، اس لیے نتیجہ ایک consistent state نہیں ہوتا۔ Postgres startup پر اسے PANIC: could not locate a valid checkpoint record کے ساتھ reject کر دیتا ہے یا بعد میں damaged page کی وجہ سے fail ہو جاتا ہے۔ حتیٰ کہ سب کچھ روک کر بنائی گئی copy بھی database کی بالکل اسی build سے وابستہ ہوتی ہے: Immich مخصوص vector-search extension versions کے ساتھ Postgres 14 image کو pin کرتا ہے، اور directory کسی اور چیز کے تحت open نہیں ہوگی۔ SQL dump plain text ہوتا ہے اور کسی بھی compatible server میں replay کیا جا سکتا ہے۔

Restore کے بعد میری Immich timeline خالی کیوں ہے؟

کیونکہ timeline database rows سے بنتی ہے، اور آپ نے database کے بغیر files restore کی ہیں۔ Immich photos کو دوبارہ دریافت کرنے کے لیے کبھی upload/ scan نہیں کرتا، اس لیے جن files کے لیے rows موجود نہیں ہوتیں وہ نظر نہیں آتیں۔ Photos خود محفوظ رہتی ہیں۔ Server روکیں، dump کو freshly initialised Postgres میں replay کریں، پھر stack start کریں۔ اگر اس کے برعکس timeline مکمل ہو لیکن ہر photo open ہونے میں fail ہو، تو مسئلہ الٹا ہے: library، upload اور profile اس directory کے اندر براہِ راست موجود نہیں ہیں جو container میں bind کی گئی ہے۔ اسے docker exec immich_server ls /data سے check کریں۔

بیک اپ میں Immich کے کن folders کو چھوڑا جا سکتا ہے؟

thumbs اور encoded-video originals سے دوبارہ generate ہو جاتے ہیں، جبکہ DB_DATA_LOCATION dump سے دوبارہ build ہو جاتا ہے، اس لیے ان میں سے کسی کو بھی backup set میں شامل کرنا ضروری نہیں۔ انہیں چھوڑنے سے storage کے بجائے restore کے بعد وقت خرچ ہوتا ہے، کیونکہ بڑی library کے لیے previews اور transcodes دوبارہ بنانا کئی گھنٹوں کی CPU لاگت رکھتا ہے۔ یہ کام missing assets کے خلاف Administration > Jobs سے چلایا جاتا ہے۔ آپ library، upload اور profile کو کبھی نہیں چھوڑ سکتے، کیونکہ ان میں ہر original کی واحد copy موجود ہوتی ہے۔

کیا میں Immich dump کو کسی نئے version میں restore کر سکتا ہوں؟

عام طور پر ہاں، کیونکہ server start کے وقت pending migrations لاگو کرتا ہے اور schema کو آگے منتقل کرتا ہے۔ الٹا عمل fail ہوتا ہے: Immich downgrade کو support نہیں کرتا، حتیٰ کہ patch releases کے درمیان بھی نہیں۔ اس لیے newer release کا dump older server میں load نہیں کیا جا سکتا۔ IMMICH_VERSION کو اس release پر pin کر کے restore کریں جس نے dump لکھا تھا، timeline کے مکمل ہونے کی تصدیق کریں، اور اس کے بعد upgrade کریں۔ ہر dump کے ساتھ version کو docker inspect --format '{{.Config.Image}}' immich_server سے record کریں، کیونکہ default IMMICH_VERSION=v3 ایک floating tag ہے جو آپ کو کوئی مفید معلومات نہیں دیتا۔