SSD Nodes Learn 🎉 VPS החל מ־$5.50/חודש
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-13

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

למדו כיצד לגבות נכון את Vaultwarden באמצעות sqlite3 .backup כדי למנוע קבצים פגומים. המדריך מפרט אילו קבצי config.json, rsa_key וקבצי מצורפים חיוניים לשחזור תקין של ה-vault שלכם.

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

גיבוי של Vaultwarden הוא עותק של כל תיקיית הנתונים, כאשר יש להעתיק את מסד הנתונים שבתוכה בצורה הנכונה. הריצו את sqlite3 db.sqlite3 ".backup out.sqlite3" במקום את cp, כיוון שהעתקה פשוטה של מסד נתונים בזמן כתיבה עלולה להניב קובץ פגום שלא ייפתח. לאחר מכן, שמרו את הקבצים הנלווים אליו; זהו החלק שאנשים נוטים לשכוח.

בהתקנת Docker, תיקיית הנתונים היא הנתיב שמיפיתם ב-/data. זהו או נתיב במערכת המארחת (host) או volume בעל שם, ו-ההבדל בין bind mounts לבין named volumes קובע היכן פיזית על הדיסק נמצא ה-vault שלכם. להלן תכולת התיקייה:

  • db.sqlite3: כל חשבון, כל פריט ב-vault, כל תיקייה וכל ארגון. אובדן קובץ זה משמעו אובדן ה-vault.
  • db.sqlite3-wal ו-db.sqlite3-shm: ה-write-ahead log (WAL) והאינדקס של הזיכרון המשותף שלו. כתיבות אחרונות נשמרות כאן עד ש-SQLite מאחד אותן לתוך הקובץ הראשי.
  • attachments/: הקבצים שמשתמשים צירפו לפריטים ב-vault, מוצפנים, בתיקייה אחת לכל פריט.
  • sends/: הקבצים שמאחורי קישורי Bitwarden Send.
  • config.json: כל הגדרה ששמרתם מדף הניהול.
  • rsa_key.pem, בתוספת rsa_key.der ו-rsa_key.pub.der בהתקנות ישנות יותר: המפתח שחותם על אסימוני התחברות (login tokens).
  • icon_cache/: סמלי אתרים שהורדו. זו התיקייה היחידה שניתן לוותר עליה, כיוון ש-Vaultwarden ימשוך אותם שוב בעת הצורך.

האם מסד הנתונים של Vaultwarden מאובטח? מה הקובץ באמת מכיל

שתי פקודות עונות על כך, ואפשר להריץ את שתיהן כבר עכשיו.

sudo apt update && sudo apt install -y sqlite3
sudo sqlite3 /opt/vaultwarden/data/db.sqlite3 "select email from users;"
sudo sqlite3 /opt/vaultwarden/data/db.sqlite3 "select name from ciphers limit 1;"

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

2.k9Qw1nQ0y7Yy2Xw==|E1r0J3l5s7d9f1g3h5j7k9==|Lm4nOp6qRs8tUv0wXy2zAb4cDe6fGh8i=

שמות פריטים, שמות משתמש, סיסמאות והערות מוצפנים על ידי הלקוח לפני שהם נשלחים, לכן השרת מאחסן טקסט מוצפן (ciphertext) שאין ביכולתו לקרוא. התחילית 2. היא סוג ההצפנה של Bitwarden, ולאחריה מופיעים וקטור אתחול (IV), הטקסט המוצפן, וקוד אימות הודעה (MAC), כולם בפורמט base64 ומופרדים על ידי |. המפתח שמפענח את המידע נגזר מסיסמת האב של החשבון, אשר לעולם אינה מגיעה לשרת בצורה שמישה. חלק זה זהה לחלוטין בין אם מריצים את Vaultwarden ובין אם את השרת הרשמי, כפי שמפורט בהשוואה בין Vaultwarden לבין Bitwarden בהתקנה עצמית.

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

מדוע העתקת הקובץ db.sqlite3 בזמן ש-Vaultwarden רץ אינה נחשבת לגיבוי

Vaultwarden מריץ כברירת מחדל את SQLite במצב WAL (ENABLE_DB_WAL=true). פעולת כתיבה נרשמת תחילה ב-db.sqlite3-wal, ורק פעולת checkpoint מאחדת אותה לתוך db.sqlite3. העתקה של db.sqlite3 בלבד תניב את מסד הנתונים כפי שהיה בנקודת ה-checkpoint האחרונה; לכן, סיסמה שנשמרה לפני עשר דקות עלולה להיות חסרה בארכיון שלכם, ללא כל התרעה על כך.

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

Error: database disk image is malformed

.backup מונע זאת מכיוון שהוא משתמש ב-Online Backup API של SQLite, אשר מתועד על ידי SQLite כדרך הנכונה להעתקת מסד נתונים שנמצא בשימוש פעיל. הוא קורא את הדפים תחת נעילת קריאה (read lock), ומתחיל מחדש אם תהליך כתיבה משנה את הקובץ תוך כדי פעולה, כך שהמידע שנכתב לדיסק מייצג רגע עקבי אחד.

ביצוע גיבוי למסד הנתונים באמצעות sqlite3 .backup

sudo apt update && sudo apt install -y sqlite3
sudo install -d -m 700 /var/backups/vaultwarden
OUT=/var/backups/vaultwarden/db-$(date '+%Y%m%d-%H%M').sqlite3
sudo sqlite3 /opt/vaultwarden/data/db.sqlite3 ".backup '$OUT'"
sudo sqlite3 "$OUT" "PRAGMA integrity_check;"

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

הכלי sqlite3 אינו כלול בתוך המכולה של Vaultwarden. האימג' בנוי על debian:trixie-slim עם ca-certificates, curl, libmariadb3, libpq5 ו-openssl, ולכן docker exec vaultwarden sqlite3 ... נכשל עם השגיאה:

exec: "sqlite3": executable file not found in $PATH

במקום זאת, יש להריץ את הפקודה על המארח (host) מול הנתיב המותקן, כפי שמבוצע בפקודות לעיל. אם הנתונים נמצאים ב-named volume, הפקודה docker volume inspect <name> תדפיס את נתיב המארח תחת /var/lib/docker/volumes/.

החל מגרסה 1.32.1, Vaultwarden כוללת פקודת גיבוי מובנית. בשרת שלכם:

docker exec -it vaultwarden /vaultwarden backup

הפקודה מריצה את VACUUM INTO וכותבת את db_YYYYMMDD_HHMMSS.sqlite3 לתוך תיקיית הנתונים. יש לשים לב לשני דברים: העותק נוצר לצד המקור על אותו דיסק, לכן מדובר בשלב ביניים (staging) ולא בגיבוי מלא. בנוסף, הפקודה תומכת ב-SQLite בלבד: בשימוש ב-MariaDB או ב-PostgreSQL הפעולה תיעצר עם The database type is not SQLite. Backups only works for SQLite databases.

The files people forget

attachments/ holds ciphertext under opaque names. The database row for each attachment carries its encrypted file name and the key material a client needs to decrypt the file. Attachments without the database are unreadable noise, and a database without the attachments gives users items whose downloads fail. Take both in the same run.

config.json holds everything you saved from the admin page, and its values take precedence over the matching environment variables. That cuts both ways: restoring an old config.json quietly overrides the settings in your compose file, and the file itself is sensitive because it can hold your SMTP password and your admin token. Store that token as an Argon2id PHC (password hashing competition) string rather than plain text. docker run --rm -it vaultwarden/server /vaultwarden hash prints one for you.

rsa_key.pem signs the JSON web tokens (JWT) that keep clients logged in. If the file is missing at startup, Vaultwarden generates a new key, so every token signed by the old one stops validating and all clients are logged out. Vault contents survive that, because they are encrypted with keys derived from the master password. Restoring the key file avoids the mass logout.

sends/ holds the files behind Send links. Missing them breaks those downloads and nothing else.

איחוד התהליך לסקריפט יחיד

#!/bin/bash
set -euo pipefail

DATA=/opt/vaultwarden/data
DEST=/var/backups/vaultwarden
STAMP=$(date '+%Y%m%d-%H%M%S')
STAGE=$(mktemp -d /tmp/vw-stage.XXXXXX)

install -d -m 700 "$DEST"
sqlite3 "$DATA/db.sqlite3" ".backup '$STAGE/db.sqlite3'"
test "$(sqlite3 "$STAGE/db.sqlite3" 'PRAGMA integrity_check;')" = "ok"
cp -a "$DATA"/rsa_key* "$STAGE/"
for extra in config.json attachments sends; do
  if [ -e "$DATA/$extra" ]; then cp -a "$DATA/$extra" "$STAGE/"; fi
done
tar -C "$STAGE" -czf "$DEST/vw-$STAMP.tar.gz" .
chmod 600 "$DEST/vw-$STAMP.tar.gz"
rm -rf "$STAGE"
tar -tzf "$DEST/vw-$STAMP.tar.gz"

שמרו את הקובץ בשם /usr/local/sbin/vw-backup.sh, תנו לו הרשאות הרצה באמצעות chmod 700, והריצו אותו כ-root. השורה test מבצעת את הפעולה המרכזית: sqlite3 מחזיר קוד יציאה 0 גם כאשר PRAGMA integrity_check מדווח על שחיתות בנתונים, לכן השוואת הפלט ל-ok היא זו שהופכת העתקה פגומה לסקריפט שנכשל. הפקודה set -euo pipefail עוצרת את התהליך כולו, במקום לאפשר ל-tar ליצור ארכיון תקין לכאורה סביב מסד נתונים פגום.

הפקודה tar -tzf בסוף מציגה את רשימת הקבצים שגובו בפועל. עברו עליה בפעם הראשונה. עליכם לוודא את קיומם של ./db.sqlite3, ./rsa_key.pem, ./config.json ו-./attachments/, ולוודא ש-./db.sqlite3-wal אינו מופיע. הריצו את הסקריפט מדי לילה באמצעות שירות וטיימר של systemd במקום cron, אם ברצונכם לקבל פלט journalctl ויחידה שמדווחת על כשל.

אימות הגיבוי באמצעות שחזור לספריית עבודה זמנית

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

sudo install -d -m 700 /tmp/vw-check
sudo tar -C /tmp/vw-check -xzf /var/backups/vaultwarden/vw-20260805-030000.tar.gz
ls -l /tmp/vw-check
sudo sqlite3 /tmp/vw-check/db.sqlite3 "PRAGMA integrity_check;"
sudo sqlite3 /tmp/vw-check/db.sqlite3 "select count(*) from users;"
sudo sqlite3 /tmp/vw-check/db.sqlite3 "select count(*) from ciphers;"
sudo du -sh /tmp/vw-check/attachments

יש לבחון ארבע תוצאות. הפקודה integrity_check מדפיסה את ok. מספר המשתמשים חייב להתאים למספר החשבונות המוכרים לכם. מספר הצפנים (ciphers) צריך להיות קרוב לנתון הקיים בשרת החי ב-sudo sqlite3 /opt/vaultwarden/data/db.sqlite3 "select count(*) from ciphers;", והוא לעולם אינו אפס בכספת פעילה. גודל ספריית הקבצים המצורפים צריך להיות תואם לציפיות שלכם (ניתן לדלג על בדיקה זו אם לא מועלים קבצים). לאחר מכן הריצו את sudo rm -rf /tmp/vw-check, כיוון שהספרייה מכילה כעת עותק נוסף של כל הנתונים.

כלל אחד תקף בעת שחזור ידני של תיקיית נתונים: מחקו את db.sqlite3-wal ואת db.sqlite3-shm לפני הפעלת השרת. אחרת, SQLite ינסה לשחזר את מסד הנתונים באמצעות יומן (log) השייך לעותק אחר, דבר שיגרום להשחתת מסד נתונים שהגיע במצב תקין. ארכיונים שנוצרו על ידי הסקריפט לעיל לעולם אינם מכילים קבצים אלו, כיוון ש-.backup כותב מסד נתונים מלא אחד.

שחזור לשרת

פעולות אלו מתבצעות על השרת שלך, כאשר המכולה (container) עצורה. אסור ש־Vaultwarden יבצע כתיבה בזמן שתיקיית הנתונים משתנה תחתיו.

cd /opt/vaultwarden
docker compose stop vaultwarden
sudo mv data data.old.$(date '+%Y%m%d-%H%M%S')
sudo install -d -m 700 data
sudo tar -C data -xzf /var/backups/vaultwarden/vw-20260805-030000.tar.gz
sudo chown -R root:root data
docker compose start vaultwarden
docker compose logs --tail 20 vaultwarden

הפקודה chown חייבת לציין את המשתמש שעל שמו רצה המכולה. התמונה (image) הסטנדרטית רצה כ־root, לכן root:root היא הבחירה הנכונה, אלא אם הגדרת user: בקובץ ה-compose שלך; במקרה כזה, השתמש ב-uid וב-gid המתאימים. תיקיית נתונים שהשרת אינו יכול לכתוב אליה תציג דף התחברות שייכשל בכל בקשה, והדבר יופיע בלוגים.

עלייה תקינה מסתיימת בשורת ה-Rocket:

[INFO] Rocket has launched from http://0.0.0.0:80

לאחר מכן, התחבר דרך הדפדפן, פתח פריט כלשהו והורד קובץ מצורף. אם ההתחברות עובדת אך הורדת קבצים מצורפים נכשלת, המשמעות היא שהארכיון הכיל את מסד הנתונים אך לא את attachments/. שמור את data.old.* עד שתוודא שכל התוכן תקין, ורק אז מחק אותו. ביצוע Rollback מתבצע באותם שלושה שלבים, תוך החלפת סדר התיקיות.

אם הנתיבים שלך אינם תואמים לאלו המופיעים כאן, מדריך ההתקנה של Vaultwarden ל-VPS מציג את קובץ ה-compose שעליו מבוססות פקודות אלו.

היכן לא לשמור גיבויים

  • לא על אותו כונן שבו נמצאת תיקיית הנתונים. כשל בנפח אחסון אחד יגרום לאובדן שני העותקים, וכך גם rm -rf שגוי בנתיב הלא נכון.
  • לא על אותו שרת, גם אם מדובר בנפח אחסון שני. תוקף שהשיג גישת root יגיע לגיבויים שלך באותה סשן.
  • לא באחסון אובייקטים (object storage) ללא הצפנה, כיוון שהארכיון מכיל כתובות דוא"ל, רמזים לסיסמאות, קודי שחזור וטקסט מוצפן של הכספת, שניתן לתקוף אותם במצב offline.
  • לא רק בתוך ה-snapshots של ספק השירות. הם מאפשרים שחזור מהיר, וזה יתרון, אך הם נמצאים תחת אותו חשבון של השרת, ולכן בעיה בחשבון תגרום לאובדנם.

עותק מחוץ לאתר (offsite) הוא המקום שבו restic נכנס לתמונה, כיוון שמאגר restic מוצפן על המכונה לפני העלאת כל נתון. בשרת שלך:

sudo apt install -y restic
export RESTIC_REPOSITORY=s3:https://s3.example.com/vaultwarden-backups
export RESTIC_PASSWORD_FILE=/root/.restic-password
restic init
restic backup /var/backups/vaultwarden --tag vaultwarden
restic snapshots --tag vaultwarden
restic forget --tag vaultwarden --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

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

בדיקת השחזור לפי לוח זמנים

בחרו יום אחד בחודש. משכו את ה-snapshot העדכני ביותר לספריית עבודה זמנית באמצעות restic restore latest --tag vaultwarden --target /tmp/vw-check, הריצו את אותו PRAGMA integrity_check, בצעו ספירת שורות זהה, ולאחר מכן תעדו את התאריך ואת תוצאות הספירה. גיבוי שלא שוחזר במשך שישה חודשים הוא גיבוי במצב לא ידוע; גילוי מצבו האמיתי בזמן תקלה הוא התרחיש הגרוע ביותר.

פעם בשנה, בצעו את התהליך המלא. הריצו מכולת Vaultwarden שנייה על פורט פנוי עם תיקיית הנתונים המשוחזרת, והתחברו באמצעות חשבון אמיתי. פעולה זו מוכיחה את תקינות נתיב ה-master password מקצה לקצה, דבר שספירת שורות אינה יכולה להבטיח. restic check --read-data-subset=10% באותו לוח זמנים מוודא שהנתונים המאוחסנים ניתנים לקריאה, ולא רק מופיעים ברשימה.

FAQ

האם ניתן להעתיק את db.sqlite3 באמצעות cp בזמן ש־Vaultwarden פועל?

לא. Vaultwarden מריץ את SQLite במצב WAL, לכן כתיבות אחרונות נמצאות ב-db.sqlite3-wal וטרם הועברו ל-db.sqlite3. ביצוע cp לקובץ הראשי בלבד יגרום לאובדן שקט של נתונים אלו, והעתקה נפרדת של שני הקבצים עלולה להוביל לזוג לא תואם שיופיע מאוחר יותר כ-Error: database disk image is malformed. השתמשו ב-sqlite3 /path/db.sqlite3 ".backup '/path/out.sqlite3'" במקום זאת. כלי זה משתמש ב-Online Backup API של SQLite ומפיק קובץ עקבי אחד בזמן שהשרת ממשיך לשרת בקשות.

האם עליי לעצור את המכולה של Vaultwarden כדי לבצע גיבוי?

לא, וזו בדיוק המטרה של .backup. העתק מסד הנתונים בטוח לשימוש גם כשהשרת פועל. קובצי מצורפים (Attachments) וקבצי Send נכתבים ברגע שמשתמש מעלה אותם, לכן קובץ שנוסף בין העתקת מסד הנתונים לבין ה-tar עלול שלא להיכלל בארכיון של אותו לילה, מה שיגרום לכל היותר לאובדן קובץ מצורף אחד. אם כמה שניות של השבתה אינן מהוות בעיה, ביצוע docker compose stop לפני הסקריפט ו-docker compose start לאחריו ימנעו גם את הסיכון הקטן הזה.

מה קורה אם אני משחזר ללא קובצי rsa_key?

Vaultwarden מייצר מפתח חדש בעת העלייה. מפתח זה חותם על אסימוני JSON web tokens (JWT) ששומרים על הפעלות (sessions) פעילות, לכן כל אסימון קיים יפסיק להיות תקף, כל הלקוחות ינותקו ויידרשו להתחבר מחדש. תוכן הכספת אינו מושפע, כיוון שהוא מוצפן באמצעות מפתחות הנגזרים מהסיסמה הראשית של כל משתמש ולא באמצעות מפתח ה-RSA. שחזרו את rsa_key.pem יחד עם שאר תיקיית הנתונים ואף משתמש לא יבחין בשחזור.

האם בטוח להעלות את ארכיון הגיבוי לאחסון אובייקטים כפי שהוא?

לא. שמות פריטים, סיסמאות והערות הם טקסט מוצפן, אך כתובות דוא"ל, שמות חשבון, רמזים לסיסמאות וקודים לשחזור אימות דו-שלבי הם טקסט גלוי בתוך מסד הנתונים, ותוקף לא מקוון יכול לפצח את הטקסט המוצפן בקצב שלו. הצפינו את הארכיון לפני שהוא עוזב את השרת. מאגר restic מבצע זאת עבורכם, ו-gpg --symmetric --cipher-algo AES256 vw-20260805-030000.tar.gz מפיק קובץ מוצפן יחיד שניתן להעביר לכל יעד אחסון.

כיצד עלי לגבות את Vaultwarden אם הוא מבוסס על PostgreSQL או MariaDB?

הצעדים עבור SQLite אינם רלוונטיים, והפקודה המובנית תיכשל עם The database type is not SQLite. Backups only works for SQLite databases. בצעו dump למסד הנתונים באמצעות הכלי הייעודי שלו, pg_dump או mysqldump, ושמרו על כל שאר הכללים ללא שינוי. ה-dump צריך להיכלל בארכיון אחד יחד עם attachments/, sends/, config.json וקובצי ה-rsa_key, כשהם נלקחים באותה ריצה, מוצפנים, ומאוחסנים במיקום שאינו השרת שביצע את הגיבוי.