SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-29

Як зробити резервну копію та відновити Vaultwarden на VPS

Дізнайтеся, як безпечно копіювати базу даних Vaultwarden за допомогою sqlite3 .backup. Збережіть файли attachments, config.json та rsa_key для повного відновлення системи.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, August 5, 2026.

Що має містити резервна копія Vaultwarden

Резервна копія Vaultwarden — це копія всієї папки з даними, причому базу даних у ній потрібно копіювати правильно. Використовуйте sqlite3 db.sqlite3 ".backup out.sqlite3" замість cp, оскільки просте копіювання бази даних, у яку в цей момент записуються дані, може призвести до отримання пошкодженого файлу, який не відкриється. Після цього збережіть файли, що знаходяться поруч — це те, про що часто забувають.

При встановленні через Docker папка з даними — це те, що ви змонтували за шляхом /data. Це може бути шлях на хост-машині або іменований том (named volume), і різниця між bind mounts та named volumes визначає, де саме на диску зберігається ваш сейф. Ось що вона містить:

  • db.sqlite3: усі облікові записи, усі елементи сейфа, усі папки та організації. Втрата цього файлу означає втрату сейфа.
  • db.sqlite3-wal та db.sqlite3-shm: журнал випереджального запису (WAL) та його індекс спільної пам’яті. Останні записи зберігаються тут, доки SQLite не перенесе їх у головний файл.
  • attachments/: файли, прикріплені користувачами до елементів сейфа; вони зашифровані та розміщені в окремих каталогах для кожного елемента.
  • sends/: файли, що стоять за посиланнями Bitwarden Send.
  • config.json: усі налаштування, збережені на сторінці адміністратора.
  • rsa_key.pem, а також rsa_key.der та rsa_key.pub.der у старіших версіях: ключ, що підписує токени входу.
  • 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=

Назви елементів, імена користувачів, паролі та нотатки шифруються клієнтом перед відправкою, тому сервер зберігає шифротекст, який він не може прочитати. Префікс 2. — це тип шифрування Bitwarden, за яким слідує вектор ініціалізації (IV), шифротекст і MAC (код автентифікації повідомлення), кожен з яких представлений у форматі base64 і розділений |. Ключ, що розшифровує дані, походить від майстер-пароля облікового запису, який ніколи не потрапляє на сервер у придатному для використання вигляді. Ця частина є ідентичною незалежно від того, чи використовуєте ви Vaultwarden, чи офіційний сервер, як описано в порівнянні Vaultwarden та self-hosted Bitwarden.

Решта бази даних не зашифрована. Адреси електронної пошти, імена облікових записів, підказки до паролів і коди відновлення двофакторної автентифікації зберігаються як звичайний текст разом із метаданими, такими як час створення та інформація про те, якій організації належить елемент. Отже, сам файл резервної копії є секретним. Будь-хто, хто отримає до нього доступ, дізнається, хто ваші користувачі, і зможе атакувати зашифровані блоки в офлайн-режимі з будь-якою швидкістю, яку дозволяє їхнє обладнання. Цей єдиний факт зумовлює правила зберігання, наведені нижче: копія шифрується перед тим, як залишити сервер. Адміністративний токен — це інша частина тієї самої проблеми, і посібник із захисту self-hosted Vaultwarden детально розглядає обидва аспекти.

Чому копіювання db.sqlite3 під час роботи Vaultwarden не є резервною копією

Vaultwarden за замовчуванням використовує SQLite у режимі WAL (ENABLE_DB_WAL=true). Запис спочатку потрапляє у db.sqlite3-wal, і лише після контрольної точки (checkpoint) дані переносяться у db.sqlite3. Якщо скопіювати лише db.sqlite3, ви отримаєте стан бази даних на момент останньої контрольної точки. Отже, пароль, збережений десять хвилин тому, може бути відсутнім у вашому архіві, і система не попередить вас про це.

Копіювання всіх трьох файлів за допомогою cp також не вирішує проблему. Копії створюються з невеликою різницею в часі, тому збережений WAL може описувати версії сторінок, які вже не відповідають основному файлу. SQLite намагається відновити один файл на основі іншого, і результат виходить некоректним. Ви дізнаєтеся про це значно пізніше:

Error: database disk image is malformed

.backup дозволяє уникнути цього, оскільки використовує Online Backup API від SQLite. Документація SQLite визначає цей метод як єдиний правильний спосіб копіювання бази даних, що перебуває в активному використанні. API зчитує сторінки під 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

Запустіть її на хості для змонтованого шляху, як це роблять команди вище. Якщо дані знаходяться в іменованому томі (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 у папку з даними. Зверніть увагу на два моменти. Копія зберігається поруч із оригіналом на тому самому диску, тому це лише проміжний етап, а не повноцінна резервна копія. Крім того, це стосується лише SQLite: у разі використання MariaDB або PostgreSQL команда зупиняється з повідомленням The database type is not SQLite. Backups only works for SQLite databases.

Файли, про які забувають

attachments/ містить зашифровані дані під непрозорими іменами. Рядок бази даних для кожного вкладення містить його зашифроване ім’я файлу та ключовий матеріал, необхідний клієнту для розшифрування файлу. Вкладення без бази даних — це нечитабельний шум, а база даних без вкладень надає користувачам елементи, завантаження яких завершується помилкою. Створюйте резервні копії обох компонентів одночасно.

config.json містить усе, що ви зберегли на сторінці адміністратора, і ці значення мають пріоритет над відповідними змінними середовища. Це працює в обидва боки: відновлення старого config.json непомітно перекриває налаштування у вашому файлі compose, а сам файл є конфіденційним, оскільки може містити ваш пароль SMTP та токен адміністратора. Зберігайте цей токен як рядок Argon2id PHC (password hashing competition), а не у відкритому вигляді. docker run --rm -it vaultwarden/server /vaultwarden hash згенерує такий рядок для вас.

rsa_key.pem підписує JSON web tokens (JWT), які підтримують сесії клієнтів. Якщо файл відсутній під час запуску, Vaultwarden генерує новий ключ, тому кожен токен, підписаний старим ключем, перестає проходити валідацію, і всіх клієнтів буде вилогінено. Вміст Vault при цьому зберігається, оскільки він зашифрований ключами, отриманими з майстер-пароля. Відновлення файлу ключа дозволяє уникнути масового виходу користувачів із системи.

sends/ містить файли, що стоять за посиланнями Send. Їх відсутність призводить лише до неможливості завантаження цих файлів.

Об'єднання всього в один скрипт

#!/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 вивід і unit, що звітує про помилки.

Перевірка резервної копії шляхом відновлення у тимчасову директорію

Неперевірена резервна копія — це лише припущення. Відновлення у тимчасову директорію займає хвилину і не впливає на робочі дані.

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. Кількість користувачів має збігатися з кількістю відомих вам облікових записів. Кількість шифрів має бути близькою до актуального значення з sudo sqlite3 /opt/vaultwarden/data/db.sqlite3 "select count(*) from ciphers;" і ніколи не дорівнювати нулю для активного сховища. Розмір директорії з вкладеннями має приблизно відповідати очікуваному (цей крок можна пропустити, якщо вкладення не використовуються). Після цього запустіть sudo rm -rf /tmp/vw-check, оскільки тепер у цій директорії зберігається друга копія всіх даних.

Одне правило при відновленні будь-якої скопійованої вручну папки з даними: видаліть db.sqlite3-wal та db.sqlite3-shm перед запуском сервера. В іншому разі SQLite спробує відновити базу даних, використовуючи журнал, що належить іншій її копії, що призведе до пошкодження цілісної бази даних. Архіви, створені наведеним вище скриптом, ніколи не містять цих файлів, оскільки .backup записує один повний файл бази даних.

Відновлення на сервері

Ці команди виконуються на вашому сервері, коли контейнер зупинено. 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 потрібно вказати користувача, від імені якого працює контейнер. Стандартний образ працює як root, тому root:root є правильним варіантом, якщо ви не вказали user: у файлі compose — у такому разі використовуйте відповідні uid та gid. Якщо сервер не має прав на запис у папку з даними, сторінка входу відхилятиме всі запити, про що буде вказано в журналах.

Успішний запуск завершується рядком Rocket:

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

Після цього увійдіть через браузер, відкрийте будь-який елемент і завантажте вкладення. Якщо вхід працює, а завантаження вкладень — ні, це означає, що в архіві була база даних, але не було attachments/. Зберігайте data.old.*, доки не перевірите все, після чого видаліть його. Відкат до попереднього стану виконується за ті самі три кроки, але з іншим порядком каталогів.

Якщо ваші шляхи відрізняються від наведених, посібник зі встановлення Vaultwarden на VPS містить файл compose, на який розраховані ці команди.

Де не варто зберігати резервні копії

  • Не на тому самому диску, де розташована папка з даними. Одна несправність тому знищить обидві копії, так само як і одна помилка rm -rf у шляху.
  • Не на тому самому сервері, навіть на іншому томі. Зловмисник, який отримав права root, отримає доступ до ваших резервних копій у межах однієї сесії.
  • Не в об'єктному сховищі без шифрування, оскільки архів містить адреси електронної пошти, підказки до паролів, коди відновлення та зашифровані дані сховища, які можна атакувати офлайн.
  • Не лише у знімках (snapshots) вашого провайдера. Вони швидко відновлюються, що є перевагою, але вони знаходяться в тому самому обліковому записі, що й сервер, тому проблеми з доступом до акаунта призведуть до втрати і їх.

Віддалена копія — це те, для чого призначений 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 на каталог з архівами, а не на папку з робочими даними, щоб він завантажував узгоджену копію, яку ви вже перевірили. Зберігайте пароль від репозиторію окремо від сервера, який він захищає: якщо ви втратите цей пароль, знімки стануть нечитабельними, і це передбачено архітектурою. Якщо сховище це підтримує, надайте серверу облікові дані, які дозволяють запис, але не видалення, щоб у разі зламу сервера зловмисник не зміг стерти власну історію. Налаштування резервного копіювання за допомогою restic на VPS повністю описує роботу з репозиторієм та планувальником, а порівняння restic та BorgBackup допоможе з вибором, якщо ви ще не визначилися.

Тестування відновлення за розкладом

Оберіть один день на місяць. Витягніть найновіший знімок у тимчасову директорію за допомогою restic restore latest --tag vaultwarden --target /tmp/vw-check, виконайте той самий PRAGMA integrity_check, порівняйте кількість рядків, а потім запишіть дату та отримані результати. Резервна копія, яку ніхто не відновлював протягом шести місяців, має невідомий стан. Ви дізнаєтеся про її стан під час аварії, що є найгіршим моментом для таких відкриттів.

Раз на рік виконуйте повну процедуру відновлення. Запустіть другий контейнер Vaultwarden на вільному порті з відновленою папкою даних і увійдіть у систему за допомогою реального облікового запису. Це підтвердить працездатність шляху доступу з майстер-паролем від початку до кінця, чого не може гарантувати проста перевірка кількості рядків. 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. Копіювання бази даних є безпечним на працюючому сервері. Вкладення та файли Send записуються під час завантаження користувачем, тому файл, доданий між копіюванням бази даних і tar, може не потрапити до нічного архіву, що в найгіршому випадку призведе до втрати одного вкладення. Якщо кілька секунд простою для вас прийнятні, docker compose stop перед скриптом і docker compose start після нього усунуть навіть цю проблему.

Що станеться, якщо виконати відновлення без файлів rsa_key?

Vaultwarden згенерує новий ключ під час запуску. Цей ключ підписує JSON web tokens (JWT), які підтримують активність сесій, тому всі наявні токени перестануть бути дійсними, усіх клієнтів буде вилогінено, і їм доведеться авторизуватися знову. Вміст сховища не постраждає, оскільки він зашифрований ключами, похідними від майстер-пароля кожного користувача, а не 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. Виконайте дамп бази даних за допомогою рідного інструменту, pg_dump або mysqldump, а всі інші правила залиште без змін. Дамп має зберігатися в одному архіві разом із attachments/, sends/, config.json та файлами rsa_key, створеними за один прохід, зашифрованими та збереженими окремо від сервера, на якому вони були створені.