SSD Nodes Learn Hosting plans →
מדריכים Matt Connorמאת Matt Connor

גיבוי VPS עם Restic לשרת אחר או לאחסון S3

למדו להגדיר Restic על Ubuntu 24.04, לשלוח גיבויים מוצפנים לשרת אחר או לאחסון S3, להפעיל טיימר nightly ולבדוק שחזור בפועל.

מדוע גיבוי באותו שרת אינו גיבוי

Restic הוא כלי גיבוי חינמי בקוד פתוח, ששולח snapshots מוצפנים ומבוססי deduplication של הקבצים שלך אל repository במקום אחר: VPS שני, מחשב בבית או object storage תואם S3. במדריך הזה מגדירים אותו על Ubuntu 24.04, מההתקנה ועד repository באמצעות SFTP, גיבוי ראשון, טיימר nightly של systemd, מדיניות שמירת גיבויים ותרגול restore שמוכיח שכל התהליך פועל. יעד הגיבוי חייב להיות במכונה אחרת, משום שעותק שנמצא באותו שרת ייעלם יחד עם השרת.

תיקיית backup/ במחשב שעליו מתבצע הגיבוי מגינה עליך מפני דבר אחד בלבד: מחיקה שגויה של קובץ. היא לא שורדת כשל בדיסק, משום שהיא נמצאת באותו דיסק. היא לא שורדת תוקף עם הרשאות root, משום שהוא ימחק את העותקים תחילה. היא לא שורדת טעות בחשבון שמסירה את ה־VPS עצמו. חוות השרתים הכי לא יעילה בעולם מתבדחת על קובץ tarball בשם backup_final_v2_REAL שנמצא באותו מערך אחסון כמו הנתונים, והבדיחה עובדת משום שרבים מאיתנו הפעילו בדיוק תצורה כזאת. הכלל הוא לשמור את הגיבוי מחוץ לשרת, ו־restic הוא הדרך הפשוטה ביותר לעשות זאת.

Restic בארבע נקודות

מאגר (Repository). המקום שאליו restic כותב. זהו מבנה תיקיות בפורמט הייחודי של restic, המלא בבלוקים מוצפנים שרק restic מסוגל לקרוא. לעולם אין לערוך את המאגר ידנית; התקשורת איתו מתבצעת אך ורק דרך פקודות restic והכתובת -r.

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

Deduplication (מניעת כפילויות). restic מחלק קבצים למקטעים (chunks) מבוססי תוכן ומעלה רק את המקטעים שעדיין לא קיימים במאגר. הגיבוי הראשון מעלה את כל הנתונים; כל הרצה לאחר מכן מעלה בערך רק את מה שהשתנה. snapshot לילי של 20 GB שבו השתנו 50 MB יעלה כ-50 MB בלבד, וזו הסיבה ששמירת עשרות snapshots היא פעולה זולה.

הצפנה כברירת מחדל. מאגר restic תמיד מוצפן (AES-256). restic מסרב ליצור או לפתוח מאגר עם סיסמה ריקה אלא אם מעבירים את הדגל --insecure-no-password (בגרסאות restic 0.17.0 ומעלה), לכן מאגר שהוגדר לפי מדריך זה דורש את הסיסמה עבור כל פקודה. שרת הגיבוי או ספק האחסון רואים תמיד רק בלוקים מוצפנים. המשמעות הקריטית: אובדן הסיסמה פירושו אובדן הנתונים לצמיתות, כחלק מתכנון המערכת. שמרו עותק של הסיסמה במקום שאינו השרת הנוכחי. זהו נושא חשוב מספיק כדי שיוזכר פעמיים נוספות בהמשך.

התקנת restic ב־Ubuntu 24.04

sudo apt update && sudo apt install -y restic
restic version

ב־Ubuntu 24.04 תותקן גרסת restic 0.16.4, בעוד שהגרסה העדכנית ביותר upstream היא 0.19.1. הפער קיים משום שגרסת LTS (תמיכה ארוכת טווח) מקפיאה את גרסאות החבילות שלה. במקרה הזה אין לכך משמעות: גרסה 0.16.4 מספקת את כל הדרוש במדריך הזה. אם דרושה לכם הגרסה החדשה ביותר כדי ליהנות משיפורי הביצועים שלה, הורידו את קובץ ההפעלה הבינארי הרשמי היחיד מדף ה־GitHub releases של פרויקט restic, חלצו אותו באמצעות bunzip2 והתקינו אותו ב־/usr/local/bin/restic. אין צורך בפעולות נוספות להתקנת restic.

יצירת המאגר בשרת אחר באמצעות SFTP

נדרשת מכונת יעד: בדרך כלל משתמשים ב־VPS קטן נוסף, וכל מחשב עם שרת SSH ושטח דיסק פנוי יתאים. Restic תומך ב־SFTP (העברת קבצים באמצעות SSH), ולכן אין צורך להתקין דבר במארח הגיבוי. במדריך זה מארח הגיבוי הוא 10.0.0.12, עם משתמש בשם restic. אין לקרוא למשתמש הזה backup: Ubuntu ו־Debian מתקינים בכל התקנה חשבון מערכת שמור בשם backup (uid 34, ללא shell כניסה), ולכן adduser backup נכשל ו־ssh backup@... נכתב אל nologin.

המשימה הלילית תפעל כ־root בשרת שעליו מתבצע הגיבוי, ולכן root זקוק להתחברות באמצעות מפתח למארח הגיבוי. צרו מפתח ייעודי ללא passphrase, משום שאין אדם שיקליד אותו בשעה 3 לפנות בוקר, והעתיקו אותו:

sudo ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N "" -C "web1-restic"
sudo ssh-copy-id -i /root/.ssh/id_ed25519.pub restic@10.0.0.12
sudo ssh restic@10.0.0.12 true && echo key login works

אם מפתחות אינם מוכרים לכם, יסודות ניהול מפתחות SSH מסביר את המודל, את ההרשאות ואת אופן ביטולו של מפתח בהמשך.

כעת סיסמת המאגר. צרו סיסמה חזקה ושמרו אותה בקובץ הנגיש רק ל־root:

openssl rand -base64 32 | sudo tee /root/.restic-password
sudo chmod 600 /root/.restic-password

כעת העתיקו את הסיסמה למנהל הסיסמאות שלכם, לפני שתמשיכו. אם ה־VPS הזה יושבת, המאגר יחד עם הסיסמה הזו ישחזרו הכול; מאגר ללא הסיסמה לא ישחזר דבר.

אתחלו את המאגר:

sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password init
created restic repository 9f3c2a1b0d at sftp:restic@10.0.0.12:/srv/restic/web1

החלופה היא אחסון אובייקטים תואם S3, והיא הבחירה המתאימה כאשר אינכם רוצים להפעיל מכונה שנייה. כל bucket תואם S3 פועל באותה צורה; רק הכתובת ושני משתני האימות משתנים:

export AWS_ACCESS_KEY_ID=your-key-id
export AWS_SECRET_ACCESS_KEY=your-secret-key
sudo -E restic -r s3:https://s3.example.com/web1-backups --password-file /root/.restic-password init

כל מה שמופיע אחרי init זהה בשני היעדים. בהמשך המדריך מוצגת כתובת ה־SFTP; החליפו אותה בכתובת שלכם.

הגיבוי הראשון, עם החרגות

גבו את הנתונים שאי־אפשר להתקין מחדש, ולא את כל מערכת הקבצים. את מערכת ההפעלה אפשר לשחזר באמצעות התקנה מחדש; את התצורה ואת הנתונים שלכם אי־אפשר לשחזר כך. ב־VPS טיפוסי מדובר ב־/etc, ב־/home ובמיקומים שבהם היישומים שומרים את מצבם, כגון /srv או /var/www. החריגו מטמונים, משום שהם גדולים, משתנים מדי יום ונבנים מחדש בעצמם:

sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password backup /etc /home /srv --exclude '/home/*/.cache'
Files:        4181 new,     0 changed,     0 unmodified
Added to the repository: 731.204 MiB (312.418 MiB stored)
snapshot 5b8a3f2c saved

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

sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password snapshots

כל snapshot מציג מזהה, שעה ואת הנתיבים שהוא מכיל. משתמשים במזהים האלה כדי לבצע שחזור.

הפעלות ליליות באמצעות systemd timer

הקלדת כתובת המאגר בכל פקודה נעשית מייגעת, וגיבוי שמפעילים ידנית מפסיק להתבצע בתוך חודש. שני המצבים נפתרים באמצעות סקריפט אחד ו־timer אחד. הסקריפט מגדיר את שני משתני הסביבה ש־restic קורא, RESTIC_REPOSITORY ו־RESTIC_PASSWORD_FILE, ולכן כל פקודה בתוכו נשארת קצרה:

sudo nano /usr/local/bin/restic-backup.sh
#!/usr/bin/env bash
set -euo pipefail
export RESTIC_REPOSITORY='sftp:restic@10.0.0.12:/srv/restic/web1'
export RESTIC_PASSWORD_FILE=/root/.restic-password

restic backup /etc /home /srv --exclude '/home/*/.cache'
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check
sudo chmod 700 /usr/local/bin/restic-backup.sh

השורות forget ו־check מוסברות בשני הסעיפים הבאים. כעת נגדיר את לוח הזמנים: שירות מסוג oneshot שמפעיל את הסקריפט, ו־timer שמפעיל אותו בשעה 03:00 בכל לילה. במקרה הזה timer עדיף על שורת cron, משום שההרצה נרשמת ב־journal, ו־Persistent=true מפעיל גיבוי שהוחמץ מיד לאחר שהשרת חוזר לפעול בעקבות השבתה.

# /etc/systemd/system/restic-backup.service
[Unit]
Description=Nightly restic backup
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/restic-backup.sh
# /etc/systemd/system/restic-backup.timer
[Unit]
Description=Run the nightly restic backup

[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=15m
Persistent=true

[Install]
WantedBy=timers.target

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

sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer
sudo systemctl start restic-backup.service
sudo journalctl -u restic-backup.service -f

systemctl list-timers מציג מתי ההרצה הבאה תתבצע. אפשר גם ליצור את זוג קובצי ה־unit במקום להקליד אותם:

ToolGenerate the backup service and timer

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

גיבוי הוא בגדר שמועה עד שמשחזרים אותו

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

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

sudo -i
export RESTIC_REPOSITORY='sftp:restic@10.0.0.12:/srv/restic/web1'
export RESTIC_PASSWORD_FILE=/root/.restic-password
restic check --read-data-subset=10%

מכיוון שתת-הקבוצה נבחרת באקראי בכל פעם, התיעוד של restic מבהיר כי הרצות חוזרות אינן מבטיחות כיסוי של כל קובץ pack, ללא קשר למספר ההרצות. אם ברצונכם שהרצות חודשיות יכסו את כל המאגר מבלי להוריד את כולו בכל פעם, השתמשו בשיטת הקבוצות הקבועות: --read-data-subset=1/10 בחודש אחד, 2/10 בחודש הבא, וכן הלאה עד 10/10. restic מחלק את קובצי ה-pack לעשר קבוצות שוות בערך ובודק רק את קבוצה n, כך שמחזור מלא של עשר הרצות קורא כל קבוצה פעם אחת.

שנית, תרגול שחזור. בעודכם בתוך ה-root shell מהשלב הקודם, שחזרו תיקייה אחת אמיתית מה-snapshot האחרון למיקום זמני והשוו אותה לקבצים החיים:

restic restore latest --target /srv/restore-drill --include /etc/ssh
diff -r /etc/ssh /srv/restore-drill/etc/ssh

אם diff לא מדפיס דבר, סימן שכל בייט חזר זהה למקור, וזו ההוכחה היחידה שקובעת. מחקו את /srv/restore-drill לאחר מכן. בצעו את התרגול הזה מדי חודש, ופעם או פעמיים בשנה בצעו את הגרסה המלאה: שחזרו את ה-snapshot האחרון במלואו לשרת VPS זמני וודאו שהיישום שלכם אכן עולה ממנו. ביום שתזדקקו לכך תחת לחץ, תרצו שזו תהיה פעולה שכבר ביצעתם בשגרה.

שמירת גיבויים: forget ולאחר מכן prune

ללא מדיניות, תמונות המצב מצטברות ללא הגבלה והמאגר ממשיך לגדול. השורה forget בסקריפט מחילה מדיניות בכל לילה: --keep-daily 7 שומרת תמונת מצב אחת לכל יום בשבעת הימים האחרונים, --keep-weekly 4 שומרת תמונת מצב אחת לכל שבוע במשך ארבעה שבועות, ו־--keep-monthly 6 שומרת תמונת מצב אחת לכל חודש במשך שישה חודשים. כל תמונת מצב שאינה מוגנת באמצעות כלל נשכחת.

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

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

Restic מעתיק קבצים בזמן הקריאה שלהם, ואילו מסד נתונים כותב לקבצים שלו ברציפות. קובץ של מסד נתונים שנלכד באמצע כתיבה ישוחזר כמסד נתונים פגום, משום שההעתקה משלבת עמודים מלפני הכתיבה ומאחריה. הפתרון תקני: מגדירים למנוע מסד הנתונים ליצור export עקבי לקובץ, ולאחר מכן מאפשרים ל־restic לגבות את הקובץ.

עבור PostgreSQL, הוסיפו שורת dump לראש restic-backup.sh, לפני הפקודה restic backup, וכללו את תיקיית ה־dump בנתיבי הגיבוי:

mkdir -p /var/backups/db
sudo -u postgres pg_dump myapp | gzip > /var/backups/db/myapp.sql.gz

mysqldump ממלא את אותו תפקיד עבור MariaDB ו־MySQL. לדוגמה מלאה של התבנית, סעיף הגיבוי של Nextcloud מפעיל maintenance mode, יוצר dump של Postgres ומעתיק את הקבצים כמערכת עקבית אחת — בדיוק המערכת ש־restic צריך להוציא מהשרת מדי לילה. ב־SQLite משתמשים באותו עיקרון, אך באופן פשוט יותר: המדריך ל־Vaultwarden עוצר את המכולה למשך כמה שניות כדי ליצור עותק קר של db.sqlite3, וזהו הארכיון ש־restic מוציא מהשרת.

FAQ

האם גיבויי restic מוצפנים?

כן, תמיד. כל מאגר restic מוצפן ב-AES-256 ואין מצב עבודה ללא הצפנה. restic גם מסרב להשתמש בסיסמה ריקה אלא אם מעבירים את --insecure-no-password (זמין מגרסה 0.17.0), לכן מאגר שהוגדר לפי מדריך זה דורש את הסיסמה עבור כל פקודה. המכונה או הספק שמאחסנים את המאגר מחזיקים תמיד רק בלוקים מוצפנים, כך שפריצה לשרת הגיבוי לא חושפת את הקבצים שלכם. המחיר הוא מוחלט: ללא הסיסמה, איש לא יוכל לשחזר את הנתונים, לכן שמרו עותק שלה מחוץ לשרת.

האם restic מבצע גיבויים מצטברים (incremental)?

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

איך משחזרים קבצים מגיבוי של restic?

הריצו את restic snapshots כדי למצוא את ה-ID של ה-snapshot, ולאחר מכן את restic restore <id> --target /some/empty/dir כדי לשחזר אותו, תוך הוספת --include /path כדי לשחזר רק חלק ממנו. latest עובד במקום ID. restic משחזר את מבנה התיקיות המקורי תחת יעד השחזור, כך ששחזור של /etc/ssh ינחת ב-/some/empty/dir/etc/ssh. תרגלו זאת לפני שתזדקקו לכך, כי גיבוי שלא נבדק הוא בגדר שמועה בלבד.

באיזו תדירות כדאי להריץ גיבוי restic?

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

מה קורה אם איבדתי את סיסמת המאגר של restic?

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