SSD Nodes Learn 🎉 VPS $4.99/aydan başlayan
Rehberler Matt ConnorYazan Matt Connor

Vaultwarden VPS yedekleme ve geri yükleme

Canlı Vaultwarden veritabanını sqlite3 .backup ile kopyalayın; attachments, config.json ve rsa_key dosyalarını koruyup geri yüklemeyi önceden doğrulayın.

Vaultwarden yedeklemesi neleri içermelidir?

Vaultwarden yedeklemesi, tüm veri klasörünün bir kopyasıdır. Bu klasördeki veritabanı doğru yöntemle kopyalanmalıdır. cp yerine sqlite3 db.sqlite3 ".backup out.sqlite3" çalıştırılmalıdır. Yazma işlemi devam eden bir veritabanını doğrudan kopyalamak, açılamayan bir dosya oluşturabilir. Veritabanının yanında bulunan diğer dosyalar da korunmalıdır. Genellikle gözden kaçan kısım budur.

Docker kurulumunda veri klasörü, /data konumuna bağlanan klasördür. Bu, ana makinedeki bir yol veya adlandırılmış bir volume olabilir. bind mount ile adlandırılmış volume arasındaki fark, vault verilerinin diskte gerçekte nerede bulunduğunu belirler. Bu klasörde şunlar bulunur:

  • db.sqlite3: tüm hesaplar, tüm vault öğeleri, tüm klasörler ve tüm kuruluşlar. Bu dosyanın kaybedilmesi vault verilerinin kaybedilmesi anlamına gelir.
  • db.sqlite3-wal ve db.sqlite3-shm: write-ahead log (WAL) ve paylaşılan bellek dizini. SQLite bu kayıtları ana dosyaya aktarana kadar yeni yazma işlemleri burada tutulur.
  • attachments/: kullanıcıların vault öğelerine eklediği, şifrelenmiş dosyalar. Her öğenin dosyaları ayrı bir klasörde bulunur.
  • sends/: Bitwarden Send bağlantılarının arkasındaki dosyalar.
  • config.json: yönetim sayfasından kaydettiğiniz tüm ayarlar.
  • rsa_key.pem ve eski kurulumlarda rsa_key.der ile rsa_key.pub.der: oturum açma belirteçlerini imzalayan anahtar.
  • icon_cache/: indirilen web sitesi simgeleri. Atlanabilecek tek klasör budur. Vaultwarden bu simgeleri gerektiğinde yeniden indirir.

Vaultwarden veritabanım güvende mi? Dosya gerçekte ne içeriyor

Bunu iki komutla öğrenebilirsiniz. Her ikisini de hemen çalıştırabilirsiniz.

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;"

İlk komut, kullanıcılarınızın e-posta adreslerini açık metin olarak yazdırır. İkinci komut ise bir öğe adını yazdırır. Çıktı şu şekilde görünür:

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

Öğe adları, kullanıcı adları, parolalar ve notlar gönderilmeden önce istemci tarafından şifrelenir. Bu nedenle sunucu, okuyamadığı şifreli verileri depolar. 2. ön eki, Bitwarden'ın şifreleme türünü belirtir. Bunu bir başlatma vektörü (IV), şifreli veri ve bir MAC (mesaj kimlik doğrulama kodu) izler. Bu bileşenlerin her biri base64 biçimindedir ve | ile ayrılır. Verilerin şifresini çözen anahtar, hesabın ana parolasından türetilir. Ana parola, kullanılabilir bir biçimde sunucuya hiçbir zaman gönderilmez. Vaultwarden ile self-hosted Bitwarden karşılaştırmasında açıklandığı gibi, Vaultwarden veya resmi sunucu kullanılması bu kısmı değiştirmez.

Veritabanının geri kalanı şifrelenmez. E-posta adresleri, hesap adları, parola ipuçları ve iki faktörlü kurtarma kodları açık metin olarak depolanır. Oluşturma zamanları ve bir öğenin hangi kuruluşa ait olduğu gibi meta veriler de aynı yerde bulunur. Bu nedenle yedek dosyasının kendisi gizli kabul edilmelidir. Dosyaya sahip olan herkes kullanıcılarınızın kim olduğunu öğrenebilir. Ayrıca şifreli veriler üzerinde donanımının izin verdiği hızda çevrimdışı saldırılar gerçekleştirebilir. Aşağıdaki depolama kurallarının temelinde bu gerçek vardır: kopya sunucudan çıkarılmadan önce şifrelenir.

Vaultwarden çalışırken db.sqlite3 dosyasını kopyalamak neden yedekleme değildir

Vaultwarden, varsayılan olarak SQLite'ı WAL modunda çalıştırır (ENABLE_DB_WAL=true). Bir yazma işlemi önce db.sqlite3-wal dosyasına kaydedilir. Yalnızca checkpoint işlemi bu değişikliği db.sqlite3 dosyasına işler. Sadece db.sqlite3 dosyasını kopyalarsanız son checkpoint anındaki veritabanını elde edersiniz. Bu nedenle on dakika önce kaydedilen bir parola, arşivinizde herhangi bir uyarı olmadan eksik olabilir.

cp ile üç dosyanın tümünü kopyalamak da çözüm değildir. Kopyalar biraz farklı zamanlarda alınır. Bu nedenle kaydettiğiniz WAL dosyası, kaydettiğiniz ana dosyayla artık eşleşmeyen sayfa sürümlerini tanımlayabilir. SQLite daha sonra dosyalardan birini diğerinden kurtarmaya çalışır ve sonuç hatalı olur. Sorunu çok daha sonra fark edersiniz:

Error: database disk image is malformed

.backup bu sorunu, SQLite'ın Online Backup API'sini kullanarak önler. SQLite belgelerinde bu API, etkin olarak kullanılan bir veritabanını kopyalama yöntemi olarak açıklanır. Sayfaları bir okuma kilidi altında okur. Bir yazma işlemi dosyayı okuma sırasında değiştirirse işlemi yeniden başlatır. Böylece diske yazılan yedek, tek ve tutarlı bir ana karşılık gelir.

sqlite3 .backup ile veritabanı kopyasını alın

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;"

Son komut, ayrı bir satırda ok çıktısını verir. Başka bir çıktı, kopyanın kullanılamaz olduğu anlamına gelir. Bu durumda kopyayı saklamayın ve önceki kopyayı silmeyin. Dizinin tamamı çalışan bir sunucuda yürütülür. Bu nedenle hiçbir kullanıcının oturumu kapatılmaz ve hiçbir container yeniden başlatılmaz.

sqlite3 aracı Vaultwarden container'ının içinde bulunmaz. Image, debian:trixie-slim üzerinde ca-certificates, curl, libmariadb3, libpq5 ve openssl ile oluşturulduğundan docker exec vaultwarden sqlite3 ... şu hatayla başarısız olur:

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

Bunun yerine aracı host üzerinde, mount edilen path'e karşı çalıştırın. Yukarıdaki komutlar bunu yapar. Veriler named volume içinde bulunuyorsa docker volume inspect <name>, host üzerindeki path'i /var/lib/docker/volumes/ altında yazdırır.

Vaultwarden, 1.32.1 sürümünden bu yana kendi backup komutunu da sağlar. Sunucunuzda:

docker exec -it vaultwarden /vaultwarden backup

Bu komut VACUUM INTO çalıştırır ve db_YYYYMMDD_HHMMSS.sqlite3 dosyasını data klasörüne yazar. Bunun iki sonucu vardır. Kopya, aynı diskte orijinal dosyanın yanına yazılır. Bu nedenle işlem bir staging adımıdır ve henüz backup değildir. Ayrıca bu özellik yalnızca SQLite için geçerlidir. MariaDB veya PostgreSQL kullanıldığında The database type is not SQLite. Backups only works for SQLite databases hatasıyla durur.

Unutulan dosyalar

attachments/, anlaşılması güç adlar altında şifreli verileri tutar. Her ek için veritabanındaki satırda, şifrelenmiş dosya adı ve istemcinin dosyanın şifresini çözmek için ihtiyaç duyduğu anahtar materyali bulunur. Veritabanı olmadan ekler okunamayan verilerden ibarettir; ekler olmadan veritabanındaki öğelerin indirme işlemleri başarısız olur. Her ikisini de aynı çalıştırmada yedekleyin.

config.json, yönetim sayfasından kaydettiğiniz her şeyi tutar ve değerleri, eşleşen environment variable değerlerine göre önceliklidir. Bu durum iki yönlü sonuç doğurur: Eski bir config.json dosyasının geri yüklenmesi, compose dosyanızdaki ayarları sessizce geçersiz kılar. Ayrıca bu dosya hassastır; SMTP parolanızı ve admin token değerini içerebilir. Bu token değerini düz metin olarak değil, Argon2id PHC (password hashing competition) dizesi olarak saklayın. docker run --rm -it vaultwarden/server /vaultwarden hash sizin için bir tane oluşturur.

rsa_key.pem, istemcilerin oturumlarını açık tutan JSON web token (JWT) değerlerini imzalar. Başlangıçta dosya yoksa Vaultwarden yeni bir anahtar oluşturur. Bu nedenle eski anahtarla imzalanmış tüm token değerlerinin doğrulaması durur ve tüm istemcilerin oturumu kapatılır. Vault içeriği bundan etkilenmez; bunlar master password değerinden türetilen anahtarlarla şifrelenir. Anahtar dosyasının geri yüklenmesi, toplu oturum kapatmayı önler.

sends/, Send bağlantılarının arkasındaki dosyaları tutar. Bu dosyaların eksik olması, bu indirmelerin başarısız olmasına neden olur; başka bir şeyi etkilemez.

Her şeyi tek bir script içine alın

#!/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"

Dosyayı /usr/local/sbin/vw-backup.sh olarak kaydedin, chmod 700 işlemi uygulayın ve root olarak çalıştırın. test satırı gerçek bir işlem yapar: sqlite3, PRAGMA integrity_check bozulma bildirse bile 0 koduyla sonlanır. Bu nedenle çıktının ok ile karşılaştırılması, hatalı bir kopyayı başarısız bir script durumuna dönüştürür. Ardından set -euo pipefail her şeyi durdurur. Böylece tar bozuk bir veritabanının etrafında düzgün görünen bir arşiv oluşturamaz.

Son tar -tzf, gerçekten neleri aldığınızı listeler. İlk çalıştırmada çıktıyı okuyun. ./db.sqlite3, ./rsa_key.pem, ./config.json ve ./attachments/ öğelerini görmeyi; ./db.sqlite3-wal öğesinin bulunmamasını bekleyin. journalctl çıktısı ve başarısızlığı bildiren bir unit istiyorsanız, nightly çalıştırma için cron yerine bir systemd service ve timer kullanın.

Yedeklemeyi geçici bir dizine geri yükleyerek doğrulama

Test edilmemiş bir yedekleme yalnızca bir varsayımdır. Geçici bir dizine geri yükleme işlemi bir dakika sürer ve çalışan sisteme dokunmaz.

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

Dört sonuç önemlidir. integrity_check, ok çıktısını verir. Kullanıcı sayısı, bilinen hesapların sayısıyla eşleşir. Şifreli veri sayısı, sudo sqlite3 /opt/vaultwarden/data/db.sqlite3 "select count(*) from ciphers;" üzerinden alınan çalışan sistem değerine yakın olur ve kullanılan bir vault için hiçbir zaman sıfır olmaz. Ek dosyalar dizininin boyutu beklenen değere yaklaşık olarak eşit olur. Kimse ek dosya yüklemiyorsa bu kontrol atlanabilir. Ardından sudo rm -rf /tmp/vw-check çalıştırılmalıdır; çünkü bu dizin artık her şeyin ikinci bir kopyasını içerir.

Elle kopyalanmış herhangi bir veri dizinini geri yüklerken şu kurala uyulmalıdır: Sunucuyu başlatmadan önce db.sqlite3-wal ve db.sqlite3-shm silinmelidir. Aksi halde SQLite, geri yüklenen veritabanını farklı bir kopyaya ait günlük dosyasını kullanarak kurtarmaya çalışır. Bu işlem, sağlam şekilde gelen veritabanının bozulmasına neden olur. Yukarıdaki betik tarafından oluşturulan arşivlerde bu dosyalar bulunmaz; çünkü .backup tek parça bir veritabanı yazar.

Sunucuya geri yükleme

Aşağıdaki komutlar, container durdurulmuş durumdayken kendi sunucunuzda çalıştırılmalıdır. Veri klasörü değiştirildiği sırada Vaultwarden veri yazmamalıdır.

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, container’ın hangi kullanıcıyla çalıştığını belirtmelidir. Standart image root olarak çalışır. Bu nedenle compose dosyanızda user: ayarlanmamışsa root:root kullanılmalıdır. user: ayarlanmışsa ilgili uid ve gid değerleri kullanılmalıdır. Sunucunun yazamadığı bir veri klasörü, her istekte başarısız olan bir giriş sayfası görüntülenmesine neden olur. Loglarda da bu durum belirtilir.

Sağlıklı bir başlangıç, Rocket satırıyla tamamlanır:

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

Ardından tarayıcıdan giriş yapılmalı, bir öğe açılmalı ve bir ek indirilmelidir. Ek indirmeleri başarısız olurken giriş başarılıysa arşivde veritabanı vardır, ancak attachments/ yoktur. Tüm kontroller tamamlanana kadar data.old.* korunmalı, ardından silinmelidir. Geri alma işlemi, dizinlerin diğer yönde değiştirilmesi dışında aynı üç adımdan oluşur.

Kullandığınız yollar burada belirtilenlerle eşleşmiyorsa VPS için Vaultwarden kurulum kılavuzu, bu komutların temel aldığı compose dosyasını gösterir.

Yedek nereye konulmamalı

  • Veri klasörüyle aynı diske konulmamalıdır. Tek bir volume arızası her iki kopyayı da kaybettirir; yanlış yoldaki tek bir rm -rf de aynı sonucu doğurur.
  • İkinci bir volume olsa bile aynı sunucuya konulmamalıdır. Bir saldırgan root hesabına erişirse aynı oturumda yedeklere de erişir.
  • Şifreleme olmadan object storage üzerinde tutulmamalıdır; çünkü arşivde email adresleri, parola ipuçları, kurtarma kodları ve çevrimdışı olarak saldırıya uğrayabilecek vault ciphertext verileri bulunur.
  • Yalnızca provider snapshot'larında tutulmamalıdır. Hızlı geri yükleme sağlarlar ve bu nedenle kullanılmaları faydalıdır. Ancak sunucuyla aynı hesapta bulunurlar; hesapla ilgili bir sorun onları da etkiler.

Offsite bir kopya için restic kullanılabilir; çünkü restic repository, herhangi bir veri yüklenmeden önce makinede şifrelenir. Sunucuda:

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, canlı veri klasörüne değil arşiv dizinine yönlendirilmelidir. Böylece yüklenen veri, daha önce kontrol edilmiş tutarlı kopya olur. Repository parolası, koruduğu sunucudan farklı bir yerde tutulmalıdır. Bu parolanın kaybedilmesi, tasarım gereği snapshot'ların okunamaz hale gelmesine neden olur. Storage bunu destekliyorsa sunucuya yalnızca yazma yetkisi verilmeli, silme yetkisi verilmemelidir. Böylece sunucu ele geçirilse bile saldırgan sunucunun kendi geçmişini silemez. VPS üzerinde restic yedeklerini kurma, repository ve zamanlamanın tamamını açıklar. Henüz seçim yapılmadıysa restic ile BorgBackup karşılaştırması bu tercihi ele alır.

Aylık bir takvimle geri yüklemeyi test edin

Ayda bir gün belirleyin. En yeni snapshot'ı restic restore latest --tag vaultwarden --target /tmp/vw-check ile geçici bir dizine alın, aynı PRAGMA integrity_check komutunu çalıştırın, aynı satır sayılarını alın ve tarihi ve sayıları kaydedin. Altı aydır hiç geri yüklenmemiş bir yedeğin durumu bilinmiyor demektir. Bu durumu bir kesinti sırasında öğrenirsiniz ve bu, öğrenmek için en kötü zamandır.

Yılda bir kez tam testi gerçekleştirin. Geri yüklenen veri klasörünü kullanarak boşta olan bir portta ikinci bir Vaultwarden container'ı başlatın ve gerçek bir hesapla giriş yapın. Bu işlem, ana parolayla kimlik doğrulama akışının uçtan uca çalıştığını kanıtlar; hiçbir satır sayımı bunu gösteremez. Aynı takvimde restic check --read-data-subset=10% çalıştırılması, depolanan verilerin yalnızca listelenmediğini, okunabildiğini doğrular.

FAQ

C? Çalışan Vaultwarden ile cp kullanarak db.sqlite3 dosyasını kopyalayabilir miyim?

Hayır. Vaultwarden, SQLite'ı WAL modunda çalıştırır. Bu nedenle son yazma işlemleri db.sqlite3-wal içinde bulunur ve henüz db.sqlite3 dosyasına yazılmamıştır. Yalnızca ana dosyanın cp işlemiyle kopyalanması, bu verileri sessizce kaybettirir. İki dosyanın ayrı ayrı kopyalanması da daha sonra Error: database disk image is malformed olarak ortaya çıkabilecek tutarsız bir çift oluşturabilir. Bunun yerine sqlite3 /path/db.sqlite3 ".backup '/path/out.sqlite3'" kullanılmalıdır. Bu işlem, SQLite'ın Online Backup API'sini kullanır ve sunucu hizmet vermeye devam ederken tek bir tutarlı dosya oluşturur.

C? Yedek almak için Vaultwarden container'ını durdurmam gerekir mi?

Hayır. .backup kullanım amacı da budur. Veritabanı, çalışan bir sunucuda güvenli biçimde kopyalanabilir. Attachments ve Send dosyaları, kullanıcı bunlardan birini yüklediğinde yazılır. Bu nedenle veritabanı kopyası ile tar arasına eklenen bir dosya, o geceki arşivde yer almayabilir. En fazla bir attachment kaybedilir. Birkaç saniyelik kesinti sorun oluşturmuyorsa, betikten önce docker compose stop ve betikten sonra docker compose start uygulanarak bu risk de ortadan kaldırılabilir.

C? rsa_key dosyaları olmadan geri yükleme yaparsam ne olur?

Vaultwarden, başlangıç sırasında yeni bir anahtar oluşturur. Bu anahtar, oturumların geçerli kalmasını sağlayan JSON web token'larını (JWT) imzalar. Bu nedenle mevcut tüm token'lar geçersiz olur. Tüm istemcilerin oturumu kapatılır ve yeniden oturum açmaları gerekir. Vault içeriği etkilenmez. Çünkü içerik, RSA anahtarıyla değil, her kullanıcının master password değerinden türetilen anahtarlarla şifrelenir. rsa_key.pem, data klasörünün geri kalanıyla birlikte geri yüklenirse geri yükleme fark edilmez.

C? Yedek arşivini olduğu gibi object storage'a yüklemek güvenli midir?

Hayır. Öğe adları, parolalar ve notlar ciphertext biçimindedir. Ancak email adresleri, hesap adları, password ipuçları ve two-factor recovery codes veritabanında düz metin olarak bulunur. Ayrıca çevrimdışı bir saldırgan, ciphertext üzerinde kendi kaynaklarını kullanarak sınırsız deneme yapabilir. Arşiv makineden ayrılmadan önce şifrelenmelidir. restic repository bu işlemi sizin için yapar. gpg --symmetric --cipher-algo AES256 vw-20260805-030000.tar.gz ise herhangi bir storage'a aktarılabilecek tek bir şifreli dosya oluşturur.

C? Vaultwarden, PostgreSQL veya MariaDB üzerinde çalışıyorsa nasıl yedeklenir?

SQLite adımları uygulanmaz. Yerleşik komut, The database type is not SQLite. Backups only works for SQLite databases nedeniyle işlemi reddeder. Veritabanı, yerel aracıyla dışa aktarılmalıdır: pg_dump veya mysqldump kullanılmalıdır. Diğer tüm kurallar aynı kalır. Dışa aktarılan veritabanı, attachments/, sends/, config.json ve rsa_key dosyalarıyla birlikte tek bir arşivde bulunmalıdır. Bu veriler aynı çalıştırma sırasında alınmalı, arşiv şifrelenmeli ve yedeği oluşturan sunucudan farklı bir yerde saklanmalıdır.