גיבוי 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, המכילה blobs מוצפנים, ורק restic יכול לקרוא אותה. אין לערוך אותה ידנית; יש לגשת אליה באמצעות פקודות restic וכתובת -r.
Snapshot. זוהי תמונת מצב של הקבצים שגיבית בנקודת זמן מסוימת. כל הרצת גיבוי יוצרת snapshot, אפשר לשחזר כל snapshot בנפרד, וכל אחד מהם מתנהג כמו עותק מלא של הנתונים כפי שהיו באותו רגע.
Deduplication. Restic מחלק קבצים ל־chunks שנקבעים לפי התוכן, ומעלה רק chunks שה־repository עדיין לא מכיל. הגיבוי הראשון מעלה את הכול; בכל הרצה לאחר מכן מועלה, בקירוב, רק מה שהשתנה. snapshot לילי של 20 GB, שבו השתנו 50 MB, צורך כ־50 MB. לכן שמירת עשרות snapshots זולה.
הצפנה כברירת מחדל. Repository של restic תמיד מוצפן (AES-256), וכל פקודה דורשת את סיסמת ה־repository. שרת הגיבוי או ספק האחסון רואים blobs מוצפנים בלבד. המשמעות החמורה היא שאם הסיסמה אבדה, הנתונים אבודים לצמיתות, בהתאם לתכנון המערכת. שמרו עותק של הסיסמה במקום שאינו השרת הזה. זה חשוב מספיק כדי שנחזור לכך פעמיים נוספות בהמשך.
התקנת 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 initcreated 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 checksudo 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 -fsystemctl list-timers מציג מתי ההרצה הבאה תתבצע. אפשר גם ליצור את זוג קובצי ה־unit במקום להקליד אותם:
התבנית המלאה שמאחורי שני הקבצים האלה, כולל תחביר לוחות הזמנים וההנחיות להקשחה שאפשר להוסיף לשירות, מופיעה במדריך הפעלת תוכנית כשירות 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%מכיוון שתת-הקבוצה נבחרת באקראי בכל פעם, הפעלות חודשיות עוברות בהדרגה על פני כל המאגר, בלי לשלם אי-פעם על הורדה מלאה.
שנית, תרגיל השחזור. עדיין מתוך מעטפת root שהופעלה קודם, שחזרו תיקייה אמיתית אחת מה־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.gzmysqldump ממלא את אותו תפקיד עבור MariaDB ו־MySQL. לדוגמה מלאה של התבנית, סעיף הגיבוי של Nextcloud מפעיל maintenance mode, יוצר dump של Postgres ומעתיק את הקבצים כמערכת עקבית אחת — בדיוק המערכת ש־restic צריך להוציא מהשרת מדי לילה. ב־SQLite משתמשים באותו עיקרון, אך באופן פשוט יותר: המדריך ל־Vaultwarden עוצר את המכולה למשך כמה שניות כדי ליצור עותק קר של db.sqlite3, וזהו הארכיון ש־restic מוציא מהשרת.
FAQ
האם גיבויי restic מוצפנים?
כן, תמיד. כל מאגר של restic מוצפן באמצעות AES-256. אין מצב פעולה ללא הצפנה, וכל פקודה מחייבת את סיסמת המאגר. במחשב או אצל הספק שמאחסן את המאגר נשמרים רק אובייקטים מוצפנים, ולכן שרת גיבוי שנפרץ אינו חושף את הקבצים שלכם. למחיר יש משמעות מוחלטת: ללא הסיסמה, איש אינו יכול לשחזר את הנתונים. לכן יש לשמור עותק שלה מחוץ לשרת.
האם restic מבצע גיבויים אינקרמנטליים?
כל snapshot של restic מתנהג כמו גיבוי מלא, אך דורש נפח אחסון אינקרמנטלי. restic מפצל קבצים למקטעים ומעלה רק מקטעים שהמאגר עדיין אינו מכיל, ולכן הרצה לילית מעבירה בקירוב רק את השינויים שנוצרו באותו יום. בניגוד למנגנוני גיבוי אינקרמנטליים מסורתיים, אין כאן שרשרת שצריך לשחזר לפי סדר. כל snapshot ניתן לשחזור ישירות, ומחיקה של snapshot ישן לעולם אינה פוגעת בחדש יותר.
כיצד משחזרים קבצים מגיבוי restic?
הריצו את restic snapshots כדי למצוא את מזהה ה־snapshot, ולאחר מכן את restic restore <id> --target /some/empty/dir כדי לשחזר אותו. הוסיפו את --include /path כדי לשחזר רק חלק ממנו. אפשר להשתמש ב־latest במקום במזהה. restic משחזר את מבנה התיקיות המקורי תחת יעד השחזור, ולכן שחזור של /etc/ssh יוצר את הקובץ או התיקייה ב־/some/empty/dir/etc/ssh. תרגלו את התהליך לפני שתזדקקו לו, משום שגיבוי שלא נבדק הוא רק הנחה.
באיזו תדירות יש להריץ גיבוי באמצעות restic?
הרצה לילית היא תדירות מינימלית סבירה עבור שרת, והסרת כפילויות הופכת אותה לזולה: בכל הרצה מועלים רק המקטעים שהשתנו מאז ההרצה הקודמת. נתונים שמשתנים במהירות, או שאובדן של אפילו יום אחד מהם יהיה משמעותי, אפשר לגבות מדי כמה שעות באמצעות אותו דפוס של timer. התדירות היא רק החלק הפשוט. יש להפעיל גם את restic check באופן קבוע ולבצע תרגול שחזור פעם בחודש, משום שלוח זמנים ללא אימות יוצר תחושת ביטחון כוזבת.
מה קורה אם מאבדים את סיסמת מאגר ה־restic?
לא ניתן לשחזר את הגיבויים. להצפנה של restic אין דלת אחורית ואין אפשרות לאיפוס, ולכן הסיסמה חשובה כמו הגיבויים עצמם. שמרו עותק שלה במנהל הסיסמאות שלכם ובכל מקום עמיד נוסף שאינו השרת שמגובה. כל עוד יש לכם גישה למאגר, restic key add יכול לרשום סיסמה נוספת לאותו מאגר וכך לספק לכם סיסמה חלופית.