Cara Backup dan Restore Vaultwarden di VPS
Ketahui cara sandaran Vaultwarden yang betul menggunakan sqlite3 .backup. Pastikan fail db.sqlite3, attachments, config.json dan rsa_key anda selamat sebelum bencana berlaku.
Perkara yang perlu ada dalam sandaran Vaultwarden
Sandaran Vaultwarden ialah salinan keseluruhan folder data, dan pangkalan data di dalamnya mesti disalin dengan cara yang betul. Jalankan sqlite3 db.sqlite3 ".backup out.sqlite3" dan bukannya cp, kerana salinan terus pangkalan data yang sedang ditulis boleh menghasilkan fail yang tidak boleh dibuka. Kemudian, simpan fail-fail yang berada di sebelahnya; ini adalah bahagian yang sering dilupakan orang.
Pada pemasangan Docker, folder data adalah apa sahaja yang anda lekapkan (mount) pada /data. Ia sama ada laluan pada hos atau volum bernama, dan perbezaan antara bind mount dan volum bernama menentukan di mana lokasi sebenar vault anda pada cakera. Berikut adalah kandungan folder tersebut:
db.sqlite3: setiap akaun, setiap item vault, setiap folder dan setiap organisasi. Kehilangan fail ini bermakna kehilangan vault.db.sqlite3-waldandb.sqlite3-shm: write-ahead log (WAL) dan indeks memori kongsinya. Penulisan terkini disimpan di sini sehingga SQLite menggabungkannya ke dalam fail utama.attachments/: fail yang dilampirkan oleh pengguna pada item vault, disulitkan, dalam satu direktori bagi setiap item.sends/: fail di sebalik pautan Bitwarden Send.config.json: setiap tetapan yang anda simpan daripada halaman admin.rsa_key.pem, sertarsa_key.derdanrsa_key.pub.derpada pemasangan lama: kunci yang menandatangani token log masuk.icon_cache/: ikon laman web yang dimuat turun. Ini adalah satu-satunya direktori yang boleh anda abaikan, kerana Vaultwarden akan memuat turunnya semula apabila diperlukan.
Adakah pangkalan data Vaultwarden saya selamat? Apakah kandungan sebenar fail tersebut
Dua arahan menjawab persoalan ini, dan anda boleh menjalankan kedua-duanya sekarang.
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;"Arahan pertama memaparkan alamat e-mel pengguna anda dalam teks jelas. Arahan kedua memaparkan satu nama item, dan ia kelihatan seperti ini:
2.k9Qw1nQ0y7Yy2Xw==|E1r0J3l5s7d9f1g3h5j7k9==|Lm4nOp6qRs8tUv0wXy2zAb4cDe6fGh8i=Nama item, nama pengguna, kata laluan dan nota disulitkan oleh klien sebelum dihantar, jadi pelayan hanya menyimpan teks sifer yang tidak boleh dibacanya. Prefiks 2. ialah jenis penyulitan Bitwarden, diikuti oleh initialisation vector (IV), teks sifer, dan MAC (message authentication code), setiap satunya dalam format base64 dan dipisahkan oleh |. Kunci yang menyahsulitnya diperoleh daripada kata laluan induk akaun, yang tidak pernah sampai ke pelayan dalam bentuk yang boleh digunakan. Bahagian ini adalah sama sama ada anda menjalankan Vaultwarden atau pelayan rasmi, seperti yang diterangkan dalam perbandingan antara Vaultwarden dan Bitwarden yang dihoskan sendiri.
Selebih daripada pangkalan data tersebut tidak disulitkan. Alamat e-mel, nama akaun, pembayang kata laluan dan kod pemulihan dua faktor disimpan sebagai teks biasa, bersebelahan dengan metadata seperti masa penciptaan dan organisasi mana yang memiliki sesuatu item. Oleh itu, fail sandaran itu sendiri adalah rahsia. Sesiapa yang memegangnya akan mengetahui siapa pengguna anda, dan boleh menyerang gumpalan data tersulit secara luar talian pada kelajuan yang dibenarkan oleh perkakasan mereka. Fakta tunggal itu mendorong peraturan penyimpanan di bawah: salinan tersebut disulitkan sebelum ia meninggalkan pelayan.
Mengapa menyalin db.sqlite3 semasa Vaultwarden berjalan bukan satu sandaran
Vaultwarden menjalankan SQLite dalam mod WAL secara lalai (ENABLE_DB_WAL=true). Penulisan akan masuk ke db.sqlite3-wal terlebih dahulu, dan hanya proses checkpoint yang akan menggabungkannya ke dalam db.sqlite3. Jika anda menyalin db.sqlite3 sahaja, anda akan mendapat pangkalan data setakat checkpoint terakhir, jadi kata laluan yang disimpan sepuluh minit lalu mungkin tiada dalam arkib anda tanpa sebarang amaran.
Menyalin ketiga-tiga fail dengan cp juga bukan penyelesaiannya. Salinan tersebut diambil pada saat yang sedikit berbeza, jadi fail WAL yang anda simpan mungkin menerangkan versi halaman yang tidak lagi sepadan dengan fail utama yang anda simpan. SQLite kemudiannya akan cuba memulihkan satu daripada yang lain dan hasilnya adalah salah. Anda hanya akan menyedarinya jauh kemudian:
Error: database disk image is malformed.backup mengelakkan perkara ini kerana ia menggunakan Online Backup API milik SQLite, yang didokumenkan oleh SQLite sebagai cara untuk menyalin pangkalan data yang mungkin sedang digunakan secara aktif. Ia membaca halaman di bawah kunci baca (read lock), dan ia akan bermula semula jika penulis mengubah fail di bawahnya, jadi apa yang disimpan ke cakera adalah satu detik yang konsisten.
Ambil salinan pangkalan data dengan 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;"Perintah terakhir mencetak ok pada barisnya sendiri. Sebarang output lain bermakna salinan tersebut tidak boleh digunakan, jadi jangan simpan salinan itu dan jangan padam salinan sebelumnya. Keseluruhan urutan ini dijalankan terhadap pelayan yang sedang aktif, jadi tiada pengguna yang dilog keluar dan tiada bekas (container) yang dimulakan semula.
Alat sqlite3 tidak disertakan di dalam bekas Vaultwarden. Imej tersebut dibina pada debian:trixie-slim dengan ca-certificates, curl, libmariadb3, libpq5 dan openssl, jadi docker exec vaultwarden sqlite3 ... gagal dengan ralat:
exec: "sqlite3": executable file not found in $PATHJalankan perintah tersebut pada hos terhadap laluan yang dilekap (mounted path) sebagai ganti, iaitu apa yang dilakukan oleh perintah di atas. Jika data berada dalam volum bernama, docker volume inspect <name> akan mencetak laluan hos di bawah /var/lib/docker/volumes/.
Vaultwarden juga telah menyertakan perintah sandarannya sendiri sejak versi 1.32.1. Pada pelayan anda:
docker exec -it vaultwarden /vaultwarden backupIa menjalankan VACUUM INTO dan menulis db_YYYYMMDD_HHMMSS.sqlite3 ke dalam folder data. Dua perkara perlu diambil perhatian. Salinan tersebut disimpan bersebelahan dengan fail asal pada cakera yang sama, jadi ia merupakan langkah penyediaan (staging) dan belum lagi dianggap sebagai sandaran. Selain itu, ia hanya untuk SQLite: pada MariaDB atau PostgreSQL, ia akan berhenti dengan The database type is not SQLite. Backups only works for SQLite databases.
Fail yang sering dilupakan
attachments/ menyimpan teks sifer di bawah nama yang legap. Baris pangkalan data bagi setiap lampiran membawa nama fail yang disulitkan serta bahan kunci yang diperlukan oleh klien untuk menyahsulit fail tersebut. Lampiran tanpa pangkalan data hanyalah data yang tidak boleh dibaca, dan pangkalan data tanpa lampiran memberikan pengguna item yang gagal dimuat turun. Ambil kedua-duanya dalam satu proses yang sama.
config.json menyimpan segala yang anda simpan daripada halaman admin, dan nilainya mengatasi pemboleh ubah persekitaran yang sepadan. Ini mempunyai dua kesan: memulihkan config.json yang lama akan mengatasi tetapan dalam fail compose anda secara senyap, dan fail itu sendiri adalah sensitif kerana ia boleh menyimpan kata laluan SMTP dan token admin anda. Simpan token tersebut sebagai rentetan Argon2id PHC (password hashing competition) dan bukannya teks biasa. docker run --rm -it vaultwarden/server /vaultwarden hash akan mencetaknya untuk anda.
rsa_key.pem menandatangani JSON web tokens (JWT) yang memastikan klien kekal log masuk. Jika fail ini tiada semasa permulaan, Vaultwarden akan menjana kunci baharu, menyebabkan setiap token yang ditandatangani oleh kunci lama tidak lagi sah dan semua klien akan dilog keluar. Kandungan Vault terselamat daripada perkara ini kerana ia disulitkan dengan kunci yang diperoleh daripada kata laluan induk. Memulihkan fail kunci tersebut akan mengelakkan log keluar beramai-ramai.
sends/ menyimpan fail di sebalik pautan Send. Kehilangan fail ini hanya akan menyebabkan muat turun tersebut gagal dan tiada kesan lain.
Satukan semuanya dalam satu skrip
#!/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"Simpan sebagai /usr/local/sbin/vw-backup.sh, chmod 700 fail tersebut, dan jalankannya sebagai root. Baris test melaksanakan tugas utama: sqlite3 akan keluar dengan status 0 walaupun PRAGMA integrity_check melaporkan kerosakan, jadi membandingkan output dengan ok adalah cara untuk memastikan salinan yang rosak menyebabkan skrip gagal. set -euo pipefail kemudian akan menghentikan segala proses, daripada membiarkan tar membina arkib yang kemas di sekeliling pangkalan data yang rosak.
Arahan tar -tzf terakhir menyenaraikan apa yang sebenarnya telah anda peroleh. Semak fail tersebut pada kali pertama. Anda perlu mencari ./db.sqlite3, ./rsa_key.pem, ./config.json dan ./attachments/, serta memastikan tiada ./db.sqlite3-wal. Jalankan skrip ini setiap malam menggunakan systemd service dan timer dan bukannya cron jika anda mahukan output journalctl serta unit yang melaporkan kegagalan.
Sahkan sandaran dengan memulihkannya ke dalam direktori sementara
Sandaran yang tidak diuji hanyalah satu andaian. Proses pemulihan ke dalam direktori sementara hanya mengambil masa seminit dan tidak menjejaskan data sebenar.
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/attachmentsEmpat hasil adalah penting. integrity_check mencetak ok. Bilangan pengguna mestilah sepadan dengan jumlah akaun yang anda ketahui. Bilangan cipher mestilah hampir dengan angka sebenar daripada sudo sqlite3 /opt/vaultwarden/data/db.sqlite3 "select count(*) from ciphers;", dan ia tidak boleh menjadi sifar bagi vault yang sedang digunakan. Saiz direktori lampiran mestilah lebih kurang seperti yang dijangkakan; anda boleh melangkau langkah ini jika tiada sesiapa memuat naik lampiran. Kemudian, jalankan sudo rm -rf /tmp/vw-check kerana direktori tersebut kini menyimpan salinan kedua bagi segala-galanya.
Satu peraturan apabila anda memulihkan mana-mana folder data yang disalin secara manual: padam db.sqlite3-wal dan db.sqlite3-shm sebelum memulakan pelayan. Jika tidak, SQLite akan cuba memulihkan pangkalan data yang dipulihkan menggunakan log yang tergolong dalam salinan lain, dan ini akan merosakkan pangkalan data yang sebenarnya dalam keadaan baik. Arkib yang dihasilkan oleh skrip di atas tidak mengandungi fail tersebut kerana .backup menulis satu pangkalan data yang lengkap.
Pemulihan ke pelayan
Proses ini dijalankan pada pelayan anda sendiri, dengan bekas (container) dihentikan. Vaultwarden tidak boleh menulis data semasa folder data diubah di bawahnya.
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 vaultwardenchown mestilah menamakan pengguna yang menjalankan bekas tersebut. Imej standard berjalan sebagai root, jadi root:root adalah tepat kecuali anda menetapkan user: dalam fail compose anda; dalam kes itu, gunakan uid dan gid tersebut. Folder data yang tidak boleh ditulis oleh pelayan akan menyebabkan halaman log masuk gagal dalam setiap permintaan, dan log akan memaparkannya.
Permulaan yang sihat berakhir dengan baris Rocket:
[INFO] Rocket has launched from http://0.0.0.0:80Kemudian, log masuk daripada pelayar, buka satu item, dan muat turun satu lampiran. Log masuk yang berjaya sementara muat turun lampiran gagal bermakna arkib membawa pangkalan data tetapi bukan attachments/. Simpan data.old.* sehingga semua perkara tersebut disahkan, kemudian padamkannya. Proses untuk kembali ke keadaan asal (rollback) adalah tiga langkah yang sama dengan direktori yang ditukar arahnya.
Jika laluan anda tidak sepadan dengan yang dinyatakan di sini, panduan pemasangan Vaultwarden untuk VPS menunjukkan fail compose yang diandaikan oleh arahan-arahan ini.
Tempat yang tidak sepatutnya untuk menyimpan sandaran
- Jangan simpan pada cakera yang sama dengan folder data. Satu volum yang gagal akan memusnahkan kedua-dua salinan, begitu juga dengan satu
rm -rfpada laluan yang salah. - Jangan simpan pada pelayan yang sama, walaupun pada volum kedua. Penyerang yang mendapat akses root akan mencapai sandaran anda dalam sesi yang sama.
- Jangan simpan dalam storan objek tanpa penyulitan, kerana arkib tersebut mengandungi alamat e-mel, pembayang kata laluan, kod pemulihan dan teks sifer peti simpanan yang boleh diserang secara luar talian.
- Jangan hanya bergantung pada syot kilat (snapshot) pembekal anda. Ia memulihkan data dengan pantas, yang merupakan kelebihan, tetapi ia berada dalam akaun yang sama dengan pelayan, jadi masalah akaun akan menyebabkan sandaran tersebut turut hilang.
Salinan di luar tapak (offsite) adalah kegunaan utama restic, kerana repositori restic disulitkan pada mesin sebelum sebarang data dimuat naik. Pada pelayan anda:
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 --pruneHalakan restic ke direktori arkib dan bukan ke folder data langsung, supaya apa yang dimuat naik adalah salinan konsisten yang telah anda semak. Simpan kata laluan repositori di tempat lain selain daripada pelayan yang dilindunginya: jika kata laluan itu hilang, syot kilat tidak akan dapat dibaca, mengikut reka bentuknya. Di mana storan menyokongnya, berikan pelayan kelayakan yang boleh menulis tetapi tidak boleh memadam, supaya jika pelayan diceroboh, ia tidak boleh memadam sejarahnya sendiri. Menyediakan sandaran restic pada VPS merangkumi repositori dan jadual secara lengkap, dan perbandingan restic dengan BorgBackup merangkumi pilihan tersebut jika anda belum memutuskannya.
Uji pemulihan mengikut jadual
Pilih satu hari setiap bulan. Tarik snapshot terbaharu ke dalam direktori sementara menggunakan restic restore latest --tag vaultwarden --target /tmp/vw-check, jalankan PRAGMA integrity_check yang sama, lakukan pengiraan baris yang sama, kemudian catatkan tarikh dan jumlah kiraan tersebut. Sandaran yang tidak pernah dipulihkan selama enam bulan adalah sandaran yang tidak diketahui statusnya. Anda akan mengetahui statusnya semasa gangguan berlaku, iaitu saat yang paling buruk untuk mengetahuinya.
Sekali setahun, lakukan prosedur penuh. Mulakan bekas Vaultwarden kedua pada port simpanan dengan folder data yang telah dipulihkan, kemudian log masuk menggunakan akaun sebenar. Ini membuktikan laluan kata laluan induk berfungsi dari hujung ke hujung, sesuatu yang tidak dapat dilakukan oleh pengiraan baris. restic check --read-data-subset=10% pada jadual yang sama mengesahkan bahawa data yang disimpan boleh dibaca, bukan sekadar disenaraikan.
FAQ
Bolehkah saya menyalin db.sqlite3 menggunakan cp semasa Vaultwarden sedang berjalan?
Tidak. Vaultwarden menjalankan SQLite dalam mod WAL, jadi penulisan terkini berada dalam db.sqlite3-wal dan belum lagi berada dalam db.sqlite3. cp bagi fail utama sahaja akan menyebabkan kehilangan data secara senyap, dan menyalin kedua-dua fail secara berasingan boleh menghasilkan pasangan yang tidak sepadan yang akan menyebabkan Error: database disk image is malformed kemudian hari. Gunakan sqlite3 /path/db.sqlite3 ".backup '/path/out.sqlite3'" sebaliknya. Ia menggunakan API Sandaran Dalam Talian SQLite dan menghasilkan satu fail yang konsisten semasa pelayan terus beroperasi.
Adakah saya perlu menghentikan kontena Vaultwarden untuk membuat sandaran?
Tidak, dan itulah tujuan .backup. Salinan pangkalan data adalah selamat pada pelayan yang sedang berjalan. Fail lampiran dan Send ditulis apabila pengguna memuat naiknya, jadi fail yang ditambah antara salinan pangkalan data dan tar mungkin terlepas daripada arkib malam itu, yang paling buruk hanyalah kehilangan satu lampiran. Jika beberapa saat waktu henti tidak menjadi masalah bagi anda, docker compose stop sebelum skrip dan docker compose start selepasnya akan menghapuskan risiko tersebut sepenuhnya.
Apa yang berlaku jika saya melakukan pemulihan tanpa fail rsa_key?
Vaultwarden menjana kunci baharu semasa permulaan. Kunci tersebut menandatangani JSON web tokens (JWT) yang mengekalkan sesi aktif, jadi setiap token sedia ada akan berhenti disahkan dan semua klien akan dilog keluar serta perlu log masuk semula. Kandungan peti besi tidak terjejas kerana ia disulitkan dengan kunci yang diperoleh daripada kata laluan induk setiap pengguna, bukannya dengan kunci RSA. Pulihkan rsa_key.pem bersama-sama dengan fail lain dalam folder data dan tiada sesiapa yang akan menyedari pemulihan tersebut.
Adakah arkib sandaran selamat untuk dimuat naik ke storan objek seperti sedia ada?
Tidak. Nama item, kata laluan dan nota adalah teks sifer, tetapi alamat e-mel, nama akaun, pembayang kata laluan dan kod pemulihan dua faktor adalah teks biasa dalam pangkalan data, dan penyerang luar talian boleh memecahkan teks sifer tersebut mengikut kelajuan mereka sendiri. Sulitkan arkib sebelum ia meninggalkan mesin. Repositori restic melakukan perkara itu untuk anda, dan gpg --symmetric --cipher-algo AES256 vw-20260805-030000.tar.gz menghasilkan satu fail tersulit yang boleh anda serahkan kepada mana-mana storan.
Bagaimanakah cara saya membuat sandaran Vaultwarden pada PostgreSQL atau MariaDB?
Langkah-langkah SQLite tidak terpakai, dan arahan terbina dalam akan menolak dengan The database type is not SQLite. Backups only works for SQLite databases. Buat dump pangkalan data dengan alat aslinya, pg_dump atau mysqldump, dan kekalkan setiap peraturan lain seperti biasa. Fail dump tersebut perlu berada dalam satu arkib bersama attachments/, sends/, config.json dan fail rsa_key, diambil dalam satu proses yang sama, disulitkan, dan disimpan di tempat selain daripada pelayan yang menghasilkannya.