SSD Nodes Learn Hosting plans →
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-13

גיבוי ושחזור Immich על גבי שרת VPS: המדריך המלא

למדו כיצד לגבות נכון את Immich. העתקת תיקיית Postgres אינה גיבוי תקין ועלולה להוביל לציר זמן ריק. המדריך מפרט את שלושת הרכיבים הקריטיים לשחזור בגרסה v3.1.0.

מה גיבוי של Immich חייב להכיל

גיבוי של Immich מורכב משלושה מרכיבים שנלכדו באותו רגע נתון. הקבצים המקוריים תחת UPLOAD_LOCATION. גיבוי SQL של מסד הנתונים Postgres. והקבצים .env ו-docker-compose.yml המתארים את ה-stack. שחזור משמעו הרצת הגיבוי לתוך מסד נתונים חדש בזמן ששרת ה-Immich כבוי, והפעלת שאר ה-stack רק לאחר מכן. ביצוע הפעולות בסדר שגוי יוביל למצב שבו Immich עובד, אך מציג ציר זמן ריק על גבי דיסק מלא.

הפיצול חשוב מכיוון ש-Immich שומר את המצב שלו בשני מקומות שאינם מודעים זה לזה. Postgres מחזיק את כל האלבומים, אשכולות הפנים, הקישורים המשותפים, חשבונות המשתמשים, מפתחות ה-API והנתיב השמור של כל נכס. מערכת הקבצים מחזיקה את הפיקסלים. שחזור הקבצים ללא מסד הנתונים יגרום ל-Immich לא להציג דבר. שחזור מסד הנתונים ללא הקבצים יגרום לכל נכס להיפתח כתמונה שבורה.

הפקודות כאן נכתבו עבור Immich בגרסה v3.1.0, הגרסה העדכנית בתחילת אוגוסט 2026. הפרויקט מתפתח במהירות ונוהל הגיבוי המתועד השתנה יותר מפעם אחת, לכן בדקו את הגרסה שאתם מריצים בפועל לפני העתקת פקודות כלשהן. אם ה-stack עדיין לא פעיל, התחילו עם מדריך ההתקנה של Immich וחזרו לכאן.

דעו לאן הנתיבים שלכם מצביעים

שני משתנים ב-.env קובעים את כל הפעילות בדף זה. UPLOAD_LOCATION הוא ספריית האב שאליה Immich כותב את כל המדיה. DB_DATA_LOCATION הוא ספריית הנתונים של Postgres.

ה-example.env המקורי מגדיר את UPLOAD_LOCATION=./library, וזו ברירת מחדל מבלבלת, כיוון ש-Immich יוצר לאחר מכן תיקייה בשם library בתוך הנתיב הזה. הקבצים המקוריים שלכם יגיעו ל-./library/library. הגדירו נתיב מוחלט במקום זאת, כדי שסקריפט גיבוי לעולם לא יהיה תלוי בספרייה שממנה הרצתם אותו.

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 יוצר מספר תיקיות. שלוש מהן מכילות נתונים שאף תהליך לא יכול לשחזר:

  • library: הקבצים המקוריים, מסודרים לפי תבנית האחסון שלכם.
  • upload: קבצים מקוריים שטרם הועברו למבנה התבנית, בתוספת העלאות שנמצאות בתהליך.
  • profile: תמונות פרופיל של משתמשים.

אובדן של library משמעו שהתמונה אבדה. Immich לא שומר עותק שני של קובץ מקורי בשום מקום.

מדוע העתקת תיקיית הנתונים של Postgres אינה נחשבת לגיבוי

DB_DATA_LOCATION נראה כמו יעד קל. זוהי תיקייה, ו-rsync יעתיק אותה, וההעתקה תסתיים ללא שגיאה. עם זאת, זה עדיין לא גיבוי, משתי סיבות שתוכלו לראות נכשלות.

הסיבה הראשונה היא קריעה (tearing). Postgres כותב כל שינוי תחילה ליומן ה-write-ahead log (WAL), ורק לאחר מכן מחיל אותו על קובצי הטבלאות בנקודת ביקורת (checkpoint). לכן, בכל רגע נתון, הקבצים בדיסק נמצאים באמצע תהליך כתיבה, והעתקה רציפה שלוקחת ארבע דקות קוראת את הקובץ הראשון ב-02:00 ואת האחרון ב-02:04. שני הקבצים הללו אינם שייכים לאותה טרנזקציה. כאשר תפעילו את Postgres על התוצאה, הוא יסרב לעלות עם PANIC: could not locate a valid checkpoint record, או שהוא יעלה ואז יקרוס בקריאה הראשונה של דף פגום עם invalid page in block 1234 of relation base/16384/.... אף אחד מהמקרים אינו ניתן לשחזור מהעתק זה.

הסיבה השנייה תקפה גם אם תעצרו הכל לפני כן. תיקיית נתונים של Postgres קשורה לקובצי ה-binaries המדויקים שכתבו אותה. Immich מצמיד את תמונת מסד הנתונים שלו לפי digest, נכון לעכשיו ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0. מדובר ב-Postgres 14 עם שתי תוספות (extensions) לחיפוש וקטורי שעברו קומפילציה. תיקיית נתונים שנכתבה על ידי גרסה זו לא תיפתח תחת גרסה ראשית (major version) אחרת של Postgres, והיא לא תיפתח תחת גרסה הכוללת גרסאות שונות של התוספות. שרת השחזור שלכם חייב לשחזר את התמונה במדויק. SQL dump אינו מושפע מכך: הוא טקסט, וכל שרת תואם יכול להריץ אותו מחדש.

pg_dump עוקף את בעיית הקריעה לחלוטין. הוא קורא את כל מסד הנתונים בתוך snapshot יחיד של MVCC (בקרת מקביליות מרובת גרסאות), כך שהוא רואה את מסד הנתונים בדיוק כפי שהיה ברגע אחד, בזמן שכתיבות אחרות ממשיכות ברקע. זו הסיבה שאין צורך לעצור את Postgres כדי לבצע dump.

מה ניתן להשמיט מהגיבוי

אלו נוצרים מחדש, לכן ניתן לדלג עליהם:

  • thumbs: תמונות תצוגה מקדימה ומיניאטורות (thumbnails).
  • encoded-video: סרטונים שעברו קידוד מחדש (transcoded).
  • DB_DATA_LOCATION: נתונים שנבנים מחדש מתוך ה-dump.
  • ה-volume של Docker בשם model-cache: מודלים של למידת מכונה, שניתן להוריד שוב לפי דרישה.

דילוג עליהם הוא פשרה, לא רווח חינם. בנייה מחדש של מיניאטורות וקידודים עבור ספרייה גדולה דורשת שעות של זמן מעבד ב-VPS קטן, ובזמן זה ציר הזמן יציג מצייני מיקום אפורים. ניתן להריץ אותם מחדש דרך Administration > Jobs, עם הגדרת "Generate Thumbnails" ו-"Transcode Videos" להרצה על נכסים חסרים. אם ליעד הגיבוי שלכם יש מקום, כללו אותם וחסכו את ההמתנה. אם אתם קרובים למגבלת האחסון, השמיטו אותם ותכננו את הבנייה מחדש. המדריך הערכת גודל של ספריית Immich מפרט עד כמה תיקיות אלו גדלות ביחס לקבצי המקור.

כדאי להכיר תיקייה נוספת. UPLOAD_LOCATION/backups מכילה את ה-dumps האוטומטיים של מסד הנתונים של Immich, שנכתבים מדי יום בשעה 02:00, כאשר 14 האחרונים נשמרים; ניתן להגדיר זאת תחת Administration > Settings > Backup. הם אינם תופסים מקום משמעותי והם שימושיים מאוד. הם נמצאים על אותו דיסק של הספרייה שהם מגבים, לכן הם עוזרים במקרה של הגירה (migration) שגויה, אך לא במקרה של קריסת שרת. בצעו dump משלכם בכל מקרה, כיוון ש-dump שאתם יוזמים מופק באותו רגע שבו נוצר ה-snapshot של הקבצים המשויך אליו.

ביצוע גיבוי למסד הנתונים

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 מוסיף DROP ... IF EXISTS לפני כל CREATE, כך שהגיבוי ישוחזר למסד נתונים שכבר מכיל אובייקטים במקום לעצור בראשון שבהם.

כעת, הפרט הקטן שמשבש סקריפטים של גיבוי מבלי להשאיר עקבות. הפקודה היא pipeline, וה-shell מדווח על סטטוס היציאה של הפקודה האחרונה בשרשרת. אם pg_dump נכשלת, עקב סיסמה שגויה או מכולה שאינה רצה, gzip מקבלת זרם ריק, כותבת קובץ gzip תקין לחלוטין, ומסיימת עם קוד 0. הסקריפט שלכם ידווח על הצלחה, ואתם תישאר עם גיבוי של 20 בתים. הוסיפו את pipefail בראש כל סקריפט גיבוי:

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

לאחר מכן, בדקו את התוצאה במקום להסתמך על קוד היציאה:

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

השורה הראשונה בגיבוי תקין מכילה את -- PostgreSQL database dump. קובץ בגודל של כמה מאות בתים הוא גיבוי שנכשל, ללא קשר למה שהסקריפט דיווח.

תעדו איזו גרסת build יצרה את הגיבוי, לצד הקובץ:

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

אל תסתמכו על .env לצורך זה. ה-tag הסטנדרטי IMMICH_VERSION=v3 הוא tag דינמי שעוקב אחרי כל גרסת 3.x, ולכן הוא אינו מספק מידע על ה-build הספציפי שיצר את הגיבוי. קבעו את ה-tag המדויק גם בתוך .env.

השהיית השרת וביצוע Snapshot באמצעות restic

קבצים תחת UPLOAD_LOCATION אינם בלתי-ניתנים לשינוי (immutable) כל עוד Immich פועל. השרת כותב העלאות חדשות, ומשימת תבנית האחסון מעבירה קבצים בין תיקיות. אם כלי גיבוי קורא קובץ באמצע תהליך כתיבה, הוא שומר את הבתים הללו כאילו היו הקובץ השלם, ואף גורם לא מדווח על שגיאה. עצרו את ה-container של השרת למשך זמן הריצה:

docker stop immich_server

השאירו את immich_postgres פועל, כיוון שה-dump זקוק לו. ממשק האינטרנט והאפליקציה לנייד יהיו לא זמינים עד שתפעילו את השרת מחדש, מה שבדרך כלל מקובל בשעה 03:00 בשרת ביתי.

restic מתאים כאן כיוון שהוא מבצע דה-דופליקציה והצפנה לפני שהמידע עוזב את השרת. כוונו אותו למאגר (repository) שאינו נמצא על שרת זה:

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

אחסון אובייקטים (Object storage) עובד באותה צורה, וזו האפשרות העדיפה אם ברצונכם להוציא את העותק מהחומרה שלכם לחלוטין:

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 הזה יכול להיות bucket של MinIO שאתם מריצים בעצמכם על מכונה שנייה, או כל ספק תואם S3. מאגר שנמצא על אותו דיסק של הספרייה מגן עליכם מפני מחיקה בטעות בלבד, ולא מעבר לכך.

לאחר מכן בצעו את ה-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 קורא את כל עץ הקבצים בכל הרצה, אך מעלה רק בלוקים שהוא טרם ראה. לכן, ה-snapshot הראשון מעביר את כל הספרייה שלכם, וכל snapshot לאחר מכן מעביר רק את התמונות החדשות של אותו יום.

שמירת נתונים, והמפתחות שחייבים להימצא במקום אחר

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

forget מסיר snapshots מהאינדקס. --prune הוא החלק המוחק את הנתונים שעבורם ה-snapshots הללו היו ההפניה האחרונה. הרצה של forget ללא --prune תגרום לכך שחשבון האחסון שלכם לעולם לא יקטן.

בדיקות מבנה הן פעולות זולות, לכן כדאי להריץ אחת מדי שבוע:

restic check

פעולה זו מוודאת שמטא-נתוני המאגר עקביים. היא אינה קוראת את הנתונים עצמם. פעם בחודש, קראו מחדש דגימה ובדקו אותה מול ה-hashes המתועדים שלה:

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

זוהי הבדיקה היחידה שמזהה השחתה שקטה (silent corruption) ב-backend של האחסון, כיוון שהיא מורידה בלוקים אמיתיים ומחשבת מחדש את ה-checksums שלהם. ביצוע --read-data מלא על ספריית תמונות משמעו הורדת כל המאגר, דבר הכרוך בעלויות כספיות באחסון אובייקטים עם חיוב לפי נפח, ולכן הרצת בדיקה על תת-קבוצה מתחלפת היא הגרסה שאנשים מריצים בפועל.

כעת, החלק שאנשים נוטים לדלג עליו. סיסמת מאגר restic אינה ניתנת לשחזור. אין אפשרות לאיפוס ואין תמיכה טכנית. אם העותק היחיד נמצא ב-/root/.restic-password על השרת שאתם מנסים לשחזר, הגיבויים שלכם הם רעש מוצפן. כך גם לגבי מפתח הגישה לאחסון האובייקטים ו-DB_PASSWORD מתוך .env. שמרו את כולם במקום שאינו תלוי בכך שהמכונה הזו תהיה פעילה: מודפס במגירה, או במנהל סיסמאות שרץ על חומרה אחרת. אם גם מנהל הסיסמאות מאוחסן עצמית, הוא זקוק לאותו טיפול, ו-גיבוי Vaultwarden הוא משימה בפני עצמה.

שחזור Immich בסדר הפעולות התקין

סדר השחזור הוא השלב שבו גיבויים טובים עלולים להפוך לציר זמן ריק. בצעו את הרצף הבא במארח החדש.

ראשית, החזירו את קובצי התצורה. הם מציינים איזו גרסה להריץ ולאן מצביעים הנתיבים.

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

קבעו את הגרסה לפני שמתחילים דבר. קראו את immich-version.txt, הגדירו את IMMICH_VERSION בתוך .env לתג הספציפי הזה, והניחו לגרסה החדשה ביותר כרגע. Immich אינה תומכת בביצוע downgrade, אפילו בין גרסאות patch; אם שרת חדש עולה מול dump ישן ומריץ את ה-migrations שלו, לא ניתן לחזור לאחור.

שחזרו את המדיה.

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

לאחר מכן, העבירו את library, upload ו-profile כך שיישבו ישירות בתוך הנתיב שאליו מצביע UPLOAD_LOCATION במארח הנוכחי. נתיב המארח עצמו יכול להשתנות, כיוון שקובץ ה-compose קושר את התיקייה הזו לנתיב קבוע בתוך המכולה. המבנה הפנימי בתוכה אינו יכול להשתנות.

הפעילו את מסד הנתונים לבדו. השאירו את DB_DATA_LOCATION ריק כדי ש-Postgres יאתחל אשכול (cluster) חדש.

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

pg_isready מדפיס את accepting connections ברגע שההגדרה הראשונית מסתיימת, מה שלוקח מספר שניות. docker compose create בונה את כל המכולות מבלי להפעיל אותן, וזו בדיוק המטרה בשלב זה: שרת ה-Immich אסור לו לרוץ עדיין. שרת שעולה מול מסד נתונים ריק יחיל את ה-migrations שלו, ייצור סכימה חדשה ויבקש מכם ליצור חשבון מנהל חדש, ואז תבצעו replay ל-dump תחת אפליקציה שכבר רצה.

בצעו replay ל-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

שני חלקים בתהליך הזה מבצעים את העבודה בפועל. ה-sed קיים כיוון ש-pg_dump כותב search_path ריק לתוך הפלט שלו כאמצעי בטיחות, כדי ששמות לא מוגדרים ב-dump לא יתפרשו כסכימה לא צפויה. סוגי ה-vector-search של Immich נמצאים ב-public, לכן עם search path ריק, השחזור מגיע לעמודה הראשונה שהוגדרה עם סוג vector ו-psql עוצר עם ERROR: type "vector" does not exist. החזרת public לנתיב פותרת זאת.

--single-transaction --set ON_ERROR_STOP=on עוטף את כל השחזור בטרנזקציה אחת שמתבטלת בשגיאה הראשונה. אתם מקבלים או מסד נתונים מלא או כזה שלא נגעו בו. ללא דגל זה, כשל באמצע התהליך ישאיר אתכם עם מסד נתונים שעולה ומקבל את פרטי ההתחברות שלכם, אך חסרים בו מספר לא ידוע של אלבומים, דבר שתגלו רק שבועות לאחר מכן.

כעת הפעילו את הכל.

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

המתינו לשורת הפעלה כמו Immich Server is listening on, לאחר מכן פתחו את פורט 2283 והתחברו עם פרטי הגישה הישנים שלכם, כיוון שחשבונות המשתמשים חזרו עם ה-dump. אם דף ההתחברות מציע ליצור את חשבון המנהל הראשון, מסד הנתונים לא שוחזר. עצרו וקראו שוב את הפלט של psql.

אזהרה אחת בנוגע להוראות השחזור הרשמיות, שנפתחות ב-docker compose down -v. ה--v מסיר volumes בעלי שם. בקובץ ה-compose הסטנדרטי, UPLOAD_LOCATION ו-DB_DATA_LOCATION הם bind mounts, לכן הם שורדים את הפעולה. אם שיניתם אחד מהם ל-named volume, הפקודה הזו תמחק את התמונות שלכם. קראו את קובץ ה-compose שלכם לפני שתקלידו את הפקודה.

מדוע ציר הזמן ריק לאחר שחזור

ציר הזמן נבנה על סמך רשומות במסד הנתונים. Immich לעולם אינו סורק את upload/ בעת העלייה כדי לגלות מחדש תמונות, כיוון שקובץ ללא רשומה מקושרת הוא חסר בעלים, תאריך או אלבום. לכן, טעות השחזור הנפוצה ביותר היא החזרת הקבצים ללא מסד הנתונים. Immich עולה, יוצר סכימה ריקה, ומציג מופע תקין שאינו מכיל דבר, בעוד הדיסק מלא בתמונות שלכם. שום דבר לא אבד, אך שום דבר אינו גלוי. הפתרון הוא לשחזר את ה-dump כאשר השרת עצור, בדיוק כפי שתואר לעיל.

התרחיש השני שקט יותר. מסד הנתונים משוחזר, ציר הזמן מתמלא ברשומות, אך כל נכס נכשל בפתיחה. המשמעות היא שהרשומות מצביעות על קבצים שהמכולה אינה יכולה לראות, בדרך כלל משום ש-library, upload ו-profile נמצאים רמה אחת עמוק מדי לאחר restic restore --target /restore שלא הועבר למקומו הנכון. בדקו מתוך המכולה במקום לנחש:

docker exec immich_server ls /data

קובץ ה-compose הסטנדרטי מבצע mount ל-UPLOAD_LOCATION ב-/data, לכן הפלט של הפקודה אמור להציג את library, upload ו-profile. אם מוצגת תיקייה ריקה או תיקיית srv בודדת, ה-bind mount שלכם מצביע על הרמה הלא נכונה, והרשומות עצמן תקינות.

התאמת גרסאות בין גיבוי לשחזור

Immich משחררת גרסאות בתדירות גבוהה והסכימה משתנה בהתאם, לכן dump מכיל את הסכימה של השרת שביצע אותו.

שחזור של dump ישן לשרת חדש בדרך כלל עובד, כיוון שהשרת מפעיל את ה-migrations הממתינים בעת העלייה ומקדם את הסכימה. מסלול זה נבדק לאורך רצף הגרסאות. קפיצה על פני כמה גרסאות major בצעד אחד היא המקום שבו מתרחשות תקלות; הפרויקט שומר שינויים שוברים לגרסאות major ומתעד אותם ב-changelog.

שחזור של dump חדש לשרת ישן אינו עובד כלל. ה-dump מכיל טבלאות ועמודות שהקוד הישן אינו מכיר, ו-Immich מצהירה כי ביצוע downgrade אינו נתמך, אפילו בין גרסאות patch. אין פקודת rollback שניתן להשתמש בה.

לכן, שחזור בטוח הוא תהליך שגרתי. הריצו את הגרסה המדויקת שביצעה את ה-dump, שחזרו אותו, התחברו למערכת, ודאו שציר הזמן שלם, ורק לאחר מכן בצעו שדרוג. שדרגו גרסה אחת בכל פעם, עדכנו את IMMICH_VERSION והריצו את docker compose pull && docker compose up -d לאחר כל עדכון. שמירה של גיבויים משבוע האחרון מסייעת גם כאן: אם מתברר שהגיבוי החדש ביותר נוצר במהלך שדרוג שנכשל, הגיבוי מאתמול עדיין זמין במאגר.

אימות הגיבוי מדי חודש

גיבוי שמעולם לא שוחזר הוא בגדר ניחוש בלבד. פעם בחודש, שחזרו את הגיבוי לתוך מופע זמני ובדקו תמונה אחת. תרגול זה אורך כעשרים דקות, והוא הדבר היחיד שהופך את שאר הדף הזה לתוכנית התאוששות מאסון.

restic snapshots
restic stats latest

snapshots אמור להציג את הריצה של הלילה האחרון. stats latest אמור לדווח על גודל הקרוב לזה של הספרייה שלכם, ולא על כמה מגה-בייטים בודדים.

שחזרו לתוך ספריית עבודה זמנית, רצוי על מארח (host) פנוי:

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

העתיקו את docker-compose.yml ואת .env מתוך ערכת השחזור, ולאחר מכן שנו שלושה דברים בעותק. כוונו את UPLOAD_LOCATION ואת DB_DATA_LOCATION לספריות תחת /tmp/immich-drill. פרסמו את פורט ה-web במיקום אחר, 12283:2283 במקום 2283:2283. מחקו את השורות container_name:, כיוון שקובץ ה-compose הסטנדרטי מקבע שמות כמו immich_server, כך שסטאק שני על אותו מארח יתנגש עם הראשון ו-Docker יסרב ליצור אותו.

הריצו את רצף השחזור מהסעיף הקודם: מסד הנתונים בלבד, טעינת ה-dump, ולאחר מכן docker compose up -d. כעת בצעו את ארבע הבדיקות שמוכיחות שהכל תקין.

  1. התחברו עם הסיסמה ששימשה אתכם לפני התרגול. חשבונות פעילים מעידים על כך שה-dump שוחזר בהצלחה.
  2. פתחו את ציר הזמן וגללו לחודש הישן ביותר. נכסים הפרוסים על פני כל טווח התאריכים מעידים על כך שכל השורות חזרו, ולא רק האחרונות שבהן.
  3. פתחו תמונה אחת בגודל מלא והורידו את הקובץ המקורי.
  4. השוו אותו מול אותו קובץ בספרייה החיה שלכם באמצעות sha256sum. ערכי hash תואמים מעידים על כך שהבתים שרדו את סבב הגיבוי והשחזור דרך restic.

לאחר מכן, פרקו את סביבת התרגול באמצעות docker compose down -v בתוך ספריית התרגול ומחקו את /tmp/immich-drill. רשמו את התאריך במקום שבו תראו אותו, כיוון שהערך של פעולה זו טמון אך ורק בביצועה שוב בחודש הבא. אם אתם עדיין מתלבטים באיזה שרת תמונות לבחור, ההשוואה בין PhotoPrism ל-Immich מכסה את ההבדלים בין השניים בדיוק בנקודה זו.

FAQ

האם עליי לעצור את Immich כדי לגבות אותו?

עצרו את immich_server והשאירו את immich_postgres פועל. אין צורך להשהות את מסד הנתונים, כיוון ש־pg_dump קורא מתוך snapshot מסוג MVCC ורואה מצב עקבי יחיד ללא קשר לפעולות כתיבה אחרות. הקבצים הם הסיבה לעצירה: השרת כותב העלאות חדשות ומשימת ה-storage template מעבירה קבצים בין תיקיות, לכן כלי גיבוי עלול לקרוא קובץ באמצע כתיבה ולשמור עותק חלקי ללא כל שגיאה. docker stop immich_server לפני ה-snapshot ו-docker start immich_server לאחריו מונעים את מצב ה-race הזה.

האם ניתן להעתיק את תיקיית הנתונים של Postgres במקום להריץ pg_dump?

לא. העתקה רציפה של תיקיית נתונים חיה קוראת קבצים שונים ברגעים שונים, לכן התוצאה אינה מצב עקבי אחד, ו-Postgres תדחה אותה בעת העלייה עם PANIC: could not locate a valid checkpoint record או תיכשל מאוחר יותר עקב דף פגום. אפילו העתקה שמתבצעת כשהכול עצור קשורה לגרסת מסד הנתונים המדויקת: Immich מקבעת image של Postgres 14 עם גרסאות ספציפיות של תוסף ה-vector-search, והתיקייה לא תיפתח תחת שום גרסה אחרת. גיבוי SQL הוא טקסט פשוט וניתן לשחזור לכל שרת תואם.

מדוע ציר הזמן (timeline) ב-Immich ריק לאחר שחזור?

מכיוון שציר הזמן נבנה משורות במסד הנתונים ושחזרתם את הקבצים ללא מסד הנתונים. Immich לעולם אינה סורקת את upload/ כדי לגלות מחדש תמונות, לכן קבצים ללא שורות נשארים בלתי נראים. התמונות עצמן לא נפגעו. עצרו את השרת, טענו את ה-dump לתוך Postgres מאותחל, ואז הפעילו את ה-stack. אם במקום זאת ציר הזמן מלא אך כל תמונה נכשלת בפתיחה, הבעיה הפוכה: library, upload ו-profile אינם נמצאים ישירות בתוך התיקייה הממופה לתוך ה-container. בדקו זאת עם docker exec immich_server ls /data.

אילו תיקיות של Immich ניתן להשמיט בגיבוי?

thumbs ו-encoded-video נוצרות מחדש מהמקור, ו-DB_DATA_LOCATION נבנית מחדש מה-dump, לכן אף אחת מהן לא חייבת להיות בסט הגיבוי. השמטתן חוסכת נפח אחסון לפני השחזור אך דורשת זמן עיבוד לאחריו, שכן בנייה מחדש של תצוגות מקדימות (previews) וקידודים (transcodes) עבור ספרייה גדולה דורשת שעות של CPU, ומתבצעת דרך Administration > Jobs עבור נכסים חסרים. מה שלעולם אין להשמיט הוא library, upload ו-profile, המכילים את העותק היחיד של כל קובץ מקורי.

האם ניתן לשחזר dump של Immich לגרסה חדשה יותר?

בדרך כלל כן, כיוון שהשרת מחיל את ה-migrations הממתינים בעת העלייה ומקדם את ה-schema. הכיוון ההפוך נכשל: Immich אינה תומכת ב-downgrade, אפילו בין גרסאות patch, לכן dump מגרסה חדשה יותר לא ניתן לטעינה בשרת ישן יותר. שחזרו עם IMMICH_VERSION המקובע לגרסה שכתבה את ה-dump, ודאו שציר הזמן מלא, ורק אז בצעו שדרוג. תעדו את הגרסה לצד כל dump עם docker inspect --format '{{.Config.Image}}' immich_server, כיוון ש-IMMICH_VERSION=v3 כברירת מחדל הוא תג דינמי שאינו מספק מידע.