# גיבוי ושחזור

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

Source: https://nodaro.ai/he/docs/self-hosting/backups

את Nodaro באירוח עצמי **מגבים** בפקודה אחת ו**משחזרים** בפקודה אחרת. ארכיון הגיבוי כולל את כל מה שמערך השירותים לא יכול ליצור מחדש: מסד הנתונים, המדיה שלכם, מפתח ההצפנה של המופע וה-`.env` שלכם. השחזור הוא גם הדרך היחידה לחזור לגרסה קודמת, כי מיגרציות מסד הנתונים מתקדמות רק קדימה. כדי לחזור לגרסה קודמת, משחזרים את הגיבוי שיצרתם לפני העדכון.

## מה יש בגיבוי
הסקריפט `tools/community-backup.sh` כותב ארכיון `tar.gz` אחד:

| בארכיון | מה זה |
| --- | --- |
| `db.dump` | Postgres, בפורמט custom של pg_dump: תהליכים, משתמשים, משימות ורשומות מדיה |
| `minio-data.tar` | המדיה שיצרתם: תמונות, סרטונים ואודיו |
| `encryption-key` | מפתח המופע שמצפין את מפתחות הספק ואת אסימוני ההתחברות לרשתות חברתיות. **במסד נתונים ששוחזר בלעדיו יש שורות שאף אחד לא יכול לקרוא.** |
| `env` | ה-`.env` שלכם: מפתחות ספק וסודות |
| `manifest.json` | גרסת האפליקציה ושעת הגיבוי, לסקריפט השחזור |

Redis לא נכלל בכוונה: נשמר בו רק מצב זמני של משימות.

**הארכיון שווה ערך לפרטי גישה:** 
הוא כולל את ה-`.env` שלכם ואת מפתח ההצפנה. הסקריפט מגביל את הגישה לקובץ לבעלים שלו (`chmod 600`). השאירו את ההרשאות כך, ושמרו את הארכיון כמו סיסמה. ב-Windows ל-`chmod` אין השפעה של ממש: אל תשמרו את הקובץ בתיקיות מסונכרנות או בכוננים משותפים, והגבילו את הגישה אליו בהרשאות NTFS אם אנשים אחרים משתמשים במחשב.

## יצירת גיבוי
מתיקיית ההתקנה שלכם, שבה נמצא `docker-compose.community.yml`, כשמערך השירותים **רץ**:

```bash
tools/community-backup.sh
# -> ./backups/nodaro-backup-<date>-v<version>.tar.gz
```

| אפשרות | מה היא עושה |
| --- | --- |
| `tools/community-backup.sh /path/to/backups` | כותבת את הארכיון לתיקייה אחרת |
| `COMPOSE_FILE=my-compose.yml tools/community-backup.sh` | משתמשת בקובץ Compose עם שם אחר |

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

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

```bash
docker compose -f docker-compose.community.yml stop nodaro
```

**ב-Windows**, הריצו את הסקריפטים מ-**Git Bash**, ה-shell ש-Git for Windows מתקין. PowerShell וה-bash של WSL שוברים את הנתיבים בקונטיינר.

### מתי לגבות
לפני כל עדכון לגרסה **ראשית**, שבה המספר הראשון משתנה, ובכל תדירות שהנתונים שלכם מצדיקים. שורת cron עובדת כמו שהיא:

```bash
0 3 * * * cd /path/to/install && tools/community-backup.sh >> backup.log 2>&1
```

## שחזור גיבוי
```bash
tools/community-restore.sh backups/nodaro-backup-<date>-v<version>.tar.gz
```

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

1. עוצר את האפליקציה ואת הלקוחות של מסד הנתונים, `auth` ו-`rest`, כי החיבורים הפתוחים שלהם היו חוסמים את השחזור.
2. משחזר את Postgres ובודק שהוא עובד, במקום לסמוך על קודי היציאה. כמה הודעות לא מזיקות מהאימג׳ של Supabase צפויות, והן מודפסות.
3. משחזר את המדיה ובודק שה-buckets חזרו וש-MinIO תקין. אחר כך הוא משחזר את מפתח ההצפנה ובודק את הגודל שלו ב-volume. אחר כך הוא משחזר את ה-`.env` שלכם, אחרי שהוא שומר בצד עותק של כל `.env` קיים. בדיקה שנכשלת עוצרת את הסקריפט **לפני** שהאפליקציה עולה: הפעלה בלי המפתח הנכון הייתה יוצרת מפתח חדש, וכל מפתח ספק ששוחזר היה הופך לבלתי קריא לתמיד.
4. מפעיל הכול מחדש ומחכה לבדיקת התקינות של האפליקציה עצמה. הסקריפט מדווח על הצלחה רק כשהאפליקציה עולה, ואחרת הוא יוצא עם שגיאה.

כשהשחזור מסתיים, פתחו את `http://localhost:3000/setup`. כל הכרטיסים צריכים להיות ירוקים.

## חזרה לגרסה קודמת
אין דרך לבטל מיגרציות. כדי לחזור לגרסה קודמת:

1. שחזרו את הגיבוי שנוצר **לפני** העדכון, כמו שמתואר למעלה.
2. קבעו את האימג׳ הישן יותר, למשל `ghcr.io/nodaroai/nodaro-community:v1.25.1`, ב-`NODARO_IMAGE` או ב-`docker-compose.community.yml`. תגים מלאים מהצורה `vX.Y.Z` אף פעם לא זזים.
3. הריצו `docker compose -f docker-compose.community.yml up -d nodaro`.

התגים מפורטים בדף [עדכון גרסה](https://nodaro.ai/docs/self-hosting/updating).

## גיבוי של פריסה מנוהלת
מחוץ למערך השירותים של Compose, המצב נשמר בארבעה מקומות:

| מה | איך מגינים עליו |
| --- | --- |
| **Postgres של Supabase**: תהליכים, פרופילים, משימות ורשומות מדיה | השתמשו בשחזור לנקודת זמן של Supabase, שזמין בתוכניות בתשלום, או הריצו `pg_dump` באופן קבוע. זה הגיבוי החשוב ביותר. |
| **ה-bucket של האחסון**: התמונות, הסרטונים והאודיו שנוצרו | הפעילו ניהול גרסאות ב-bucket וכלל מחזור חיים ארוך, כדי שאפשר יהיה לשחזר קבצים שנמחקו. אם צריך, הוסיפו שכפול בין אזורים להתאוששות מאסון. |
| **Redis** | אין מה לגבות. נשמר בו רק מצב זמני של משימות. אם הוא אובד, הרצות שנמצאות באמצע נכשלות, וכל השאר מתאושש מ-Postgres בהפעלה הבאה. |
| **מפתח ההצפנה של המופע**, `NODARO_ENCRYPTION_KEY` | שמרו אותו יחד עם הגיבויים של Postgres. בלעדיו אי אפשר לקרוא את השורות ששוחזרו של מפתחות הספק, של אסימוני ההתחברות לרשתות חברתיות ושל פרטי הגישה של רכיב פלט Webhook. האריחים מציגים אז `missing` (חסר), וצריך להזין את המפתחות שוב; שום דבר אחר לא נשבר. |

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

### שחזור לפרויקט Supabase חדש
שחזור לפרויקט Supabase חדש לא שומר על ההרשאות של מסד הנתונים. פונקציה שנועדה לשרת בלבד עלולה לחזור כשתפקידי הדפדפן, `anon` ו-`authenticated`, יכולים לקרוא לה. טבלה או עמודה שהמיגרציות סגרו עלולות לחזור פתוחות לקריאה או לכתיבה. אחרי כל שחזור, הציגו את פונקציות ה-`SECURITY DEFINER` שהתפקידים האלה יכולים להריץ:

```sql
SELECT p.oid::regprocedure AS function,
has_function_privilege('anon', p.oid, 'EXECUTE') AS anon,
has_function_privilege('authenticated', p.oid, 'EXECUTE') AS authenticated
FROM pg_proc p
 WHERE p.pronamespace = 'public'::regnamespace
AND p.prosecdef
AND p.prorettype NOT IN ('trigger'::regtype, 'event_trigger'::regtype)
AND (has_function_privilege('anon', p.oid, 'EXECUTE')
OR has_function_privilege('authenticated', p.oid, 'EXECUTE'))
 ORDER BY 1;
```

בתוצאה צריכות להופיע רק הפונקציות שרשומות ב-`browser_callable` בקובץ הבדיקה של מאגר הקוד, `supabase/tests/server-only-function-privileges.behavior.sql`. סגרו כל פונקציה אחרת, וציינו גם את `PUBLIC`, כי `anon` ו-`authenticated` יורשים ממנו את הרשאת ה-`EXECUTE` שניתנת לו כברירת מחדל:

```sql
REVOKE EXECUTE ON FUNCTION public.<name>(<args>) FROM PUBLIC, anon, authenticated;
GRANT EXECUTE ON FUNCTION public.<name>(<args>) TO service_role;
```

מיגרציה 598 ב-`supabase/migrations/` סוגרת את הפונקציות שמיועדות לשרת בלבד ומחזירה את הרשאות הטבלאות והעמודות כפי שהגדירו אותן המיגרציות עד אליה. אפשר להריץ אותה שוב בבטחה. כדי לבדוק מסד נתונים ששוחזר מול ההרשאות הצפויות, הריצו את קובץ הבדיקה עם `psql`. קובץ הבדיקה מבטל בסוף את כל השינויים שלו, ונעצר בדבר הראשון שהוא מוצא פתוח:

```bash
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f supabase/tests/server-only-function-privileges.behavior.sql
```

## פתרון בעיות
- **`the db service is not running` (השירות db לא רץ).** הפעילו קודם את מערך השירותים: `docker compose -f docker-compose.community.yml up -d`.
- **האריחים של מפתחות הספק מציגים `missing` אחרי שחזור.** מסד הנתונים שוחזר בלי ה-`encryption-key` התואם לו, או עם מפתח אחר. שחזרו מארכיון שכולל את המפתח, או הזינו את המפתחות שוב בדף `/setup`.
- **בדיקת השחזור נכשלה.** הסקריפט לא מוכן להשאיר בשקט מסד נתונים ששוחזר רק בחלקו. הריצו את השחזור שוב. אם הוא נכשל שוב ושוב, ייתכן שהארכיון קטוע: השוו את הגודל שלו לגודל של המקור.
- **`could not read the encryption key` (אי אפשר לקרוא את מפתח ההצפנה) בזמן גיבוי ב-Windows.** אתם לא ב-Git Bash, או שהקונטיינר של האפליקציה לא רץ. הריצו את הגיבוי שוב מ-Git Bash כשמערך השירותים רץ. הארכיון שהסקריפט הזהיר לגביו הוא לא גיבוי שאפשר להשתמש בו.
- **`media restore verification FAILED` (בדיקת שחזור המדיה נכשלה) או `encryption key verification FAILED` (בדיקת מפתח ההצפנה נכשלה).** הסקריפט נעצר בכוונה ולא הפעיל את האפליקציה. בדקו את ה-volume שהוא מציין ותקנו את הסיבה — בדרך כלל קונטיינר שנעצר או דיסק מלא — ואז הריצו את השחזור שוב. אפשר לחזור על השחזור בבטחה.

## שאלות נפוצות

### איך מגבים את Nodaro באירוח עצמי?

מתיקיית ההתקנה, כשמערך השירותים רץ, הריצו את tools/community-backup.sh. הסקריפט כותב ארכיון אחד לתיקייה ‎./backups, ובו מסד הנתונים, המדיה, מפתח ההצפנה של המופע והקובץ ‎.env שלכם.

### איך משחזרים גיבוי?

הריצו את tools/community-restore.sh עם הנתיב של הארכיון. השחזור דורס את הנתונים הקיימים, ולכן הסקריפט מבקש קודם להקליד RESTORE. לפני שהוא מפעיל שוב את האפליקציה, הוא בודק את מסד הנתונים, את המדיה ואת מפתח ההצפנה.

### למה מפתחות הספק שלי מוצגים כחסרים אחרי שחזור?

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

### האם צריך לגבות את Redis?

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

### האם אפשר להריץ את סקריפטי הגיבוי ב-Windows?

כן. ב-Windows מריצים את סקריפטי הגיבוי מ-Git Bash, ה-shell ש-Git for Windows מתקין. PowerShell וה-bash של WSL שוברים את הנתיבים בקונטיינר, ואז מפתח ההצפנה לא נכלל בארכיון.
