SSD Nodes Learn Hosting plans →
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-22

Sauvegarder et restaurer Vaultwarden sur un VPS

Utilisez sqlite3 .backup pour copier Vaultwarden à chaud, gardez les pièces jointes, config.json et les clés RSA, puis vérifiez la restauration.

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

Ce qu’une sauvegarde de Vaultwarden doit contenir

Une sauvegarde de Vaultwarden est une copie de l’intégralité du dossier de données. La base de données qu’il contient doit être copiée correctement. Exécutez sqlite3 db.sqlite3 ".backup out.sqlite3" au lieu de cp, car la copie directe d’une base de données en cours d’écriture peut produire un fichier impossible à ouvrir. Conservez ensuite les fichiers qui l’accompagnent. C’est la partie que l’on oublie le plus souvent.

Dans une installation Docker, le dossier de données correspond à ce que vous avez monté sur /data. Il peut s’agir d’un chemin sur l’hôte ou d’un volume nommé. La différence entre les bind mounts et les volumes nommés détermine l’emplacement réel de votre coffre sur le disque. Voici ce qu’il contient.

  • db.sqlite3 : chaque compte, chaque élément du coffre, chaque dossier et chaque organisation. La perte de ce fichier entraîne la perte du coffre.
  • db.sqlite3-wal et db.sqlite3-shm : le write-ahead log (WAL) et son index de mémoire partagée. Les écritures récentes y restent jusqu’à ce que SQLite les intègre au fichier principal.
  • attachments/ : les fichiers joints par les utilisateurs aux éléments du coffre, chiffrés, dans un répertoire par élément.
  • sends/ : les fichiers associés aux liens Bitwarden Send.
  • config.json : tous les paramètres enregistrés depuis la page d’administration.
  • rsa_key.pem, ainsi que rsa_key.der et rsa_key.pub.der sur les anciennes installations : la clé qui signe les jetons de connexion.
  • icon_cache/ : les icônes de sites web téléchargées. C’est le seul répertoire que vous pouvez ignorer, car Vaultwarden les télécharge de nouveau à la demande.

La base de données Vaultwarden est-elle sûre ? Ce que contient réellement le fichier

Deux commandes permettent de le vérifier, et vous pouvez les exécuter immédiatement.

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

La première affiche les adresses e-mail de vos utilisateurs en clair. La seconde affiche le nom d’un élément, qui ressemble à ceci :

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

Les noms d’éléments, les noms d’utilisateur, les mots de passe et les notes sont chiffrés par le client avant leur envoi. Le serveur stocke donc un texte chiffré qu’il ne peut pas lire. Le préfixe 2. indique le type de chiffrement de Bitwarden. Il est suivi d’un vecteur d’initialisation (IV), du texte chiffré et d’un MAC (code d’authentification de message), tous encodés en base64 et séparés par |. La clé de déchiffrement est dérivée du mot de passe maître du compte, qui n’est jamais transmis au serveur sous une forme exploitable. Ce fonctionnement est identique avec Vaultwarden et avec le serveur officiel, comme l’explique la comparaison entre Vaultwarden et Bitwarden auto-hébergé.

Le reste de la base de données n’est pas chiffré. Les adresses e-mail, les noms de compte, les indices de mot de passe et les codes de récupération de l’authentification à deux facteurs sont stockés en clair, avec des métadonnées comme les dates de création et l’organisation propriétaire d’un élément. Le fichier de sauvegarde est donc lui-même un secret. Toute personne qui le détient apprend qui sont vos utilisateurs et peut attaquer les données chiffrées hors ligne, à la vitesse permise par son matériel. Ce point détermine les règles de stockage présentées plus loin : la copie est chiffrée avant de quitter le serveur. Le token d’administration constitue l’autre aspect du même problème, et la procédure de renforcement d’un Vaultwarden auto-hébergé traite ces deux points.

Pourquoi copier db.sqlite3 pendant que Vaultwarden fonctionne ne constitue pas une sauvegarde

Vaultwarden utilise SQLite en mode WAL par défaut (ENABLE_DB_WAL=true). Une écriture est d’abord ajoutée à db.sqlite3-wal, puis un checkpoint l’intègre dans db.sqlite3. Si vous copiez uniquement db.sqlite3, vous obtenez l’état de la base au dernier checkpoint. Un mot de passe enregistré dix minutes plus tôt peut donc manquer dans votre archive, sans aucun avertissement.

Copier les trois fichiers avec cp ne résout pas le problème. Les copies sont effectuées à des moments légèrement différents. Le WAL sauvegardé peut donc contenir des versions de pages qui ne correspondent plus au fichier principal copié. SQLite récupère alors les données d’un fichier à partir de l’autre, et le résultat est incorrect. Vous ne le découvrez que bien plus tard :

Error: database disk image is malformed

.backup évite ce problème en utilisant l’Online Backup API de SQLite. SQLite documente cette API comme la méthode à utiliser pour copier une base de données potentiellement utilisée activement. Elle lit les pages avec un verrou de lecture et recommence si un writer modifie le fichier pendant l’opération. Les données écrites sur le disque correspondent donc à un état cohérent unique.

Effectuer la copie de la base de données avec 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;"

La dernière commande affiche ok sur sa propre ligne. Tout autre résultat signifie que la copie n’est pas utilisable. Ne la conservez pas et ne supprimez pas la précédente. Toute la séquence s’exécute sur un serveur en production. Aucun utilisateur n’est déconnecté et aucun conteneur n’est redémarré.

L’outil sqlite3 n’est pas présent dans le conteneur Vaultwarden. L’image est basée sur debian:trixie-slim avec ca-certificates, curl, libmariadb3, libpq5 et openssl. Par conséquent, docker exec vaultwarden sqlite3 ... échoue avec :

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

Exécutez-le sur l’hôte en ciblant le chemin monté. C’est ce que font les commandes précédentes. Si les données se trouvent dans un volume nommé, docker volume inspect <name> affiche le chemin hôte sous /var/lib/docker/volumes/.

Vaultwarden fournit également sa propre commande de sauvegarde depuis la version 1.32.1. Sur votre serveur :

docker exec -it vaultwarden /vaultwarden backup

Cette commande exécute VACUUM INTO et écrit db_YYYYMMDD_HHMMSS.sqlite3 dans le dossier de données. Deux conséquences en découlent. La copie est créée à côté de l’original, sur le même disque. Il s’agit donc d’une étape de préparation, pas encore d’une sauvegarde. Cette commande ne fonctionne également qu’avec SQLite : avec MariaDB ou PostgreSQL, elle s’arrête avec The database type is not SQLite. Backups only works for SQLite databases.

Les fichiers que l’on oublie

attachments/ contient le texte chiffré sous des noms opaques. La ligne de base de données associée à chaque pièce jointe contient son nom de fichier chiffré et le matériel cryptographique dont le client a besoin pour déchiffrer le fichier. Sans la base de données, les pièces jointes sont illisibles. Sans les pièces jointes, la base de données contient des éléments dont le téléchargement échoue. Sauvegardez les deux lors de la même exécution.

config.json contient tous les paramètres enregistrés depuis la page d’administration. Leurs valeurs sont prioritaires sur les variables d’environnement correspondantes. Cela peut poser problème dans les deux sens : la restauration d’un ancien fichier config.json remplace silencieusement les paramètres de votre fichier compose, et le fichier lui-même est sensible, car il peut contenir votre mot de passe SMTP et votre token d’administration. Stockez ce token sous forme de chaîne PHC Argon2id (password hashing competition), et non en clair. docker run --rm -it vaultwarden/server /vaultwarden hash en génère une pour vous.

rsa_key.pem signe les JSON web tokens (JWT) qui maintiennent les clients connectés. Si le fichier est absent au démarrage, Vaultwarden génère une nouvelle clé. Tous les tokens signés avec l’ancienne clé cessent alors d’être valides et tous les clients sont déconnectés. Le contenu du coffre reste intact, car il est chiffré avec des clés dérivées du mot de passe maître. La restauration du fichier de clé évite cette déconnexion générale.

sends/ contient les fichiers associés aux liens Send. Leur absence empêche ces téléchargements, sans autre conséquence.

Mettez tout dans un seul script

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

Enregistrez-le sous /usr/local/sbin/vw-backup.sh, rendez-le exécutable avec chmod 700, puis exécutez-le en tant que root. La ligne test effectue un véritable contrôle : sqlite3 renvoie le code 0 même lorsque PRAGMA integrity_check signale une corruption. La comparaison de la sortie avec ok transforme donc une copie défectueuse en échec du script. set -euo pipefail arrête ensuite toutes les opérations, au lieu de laisser tar créer une archive propre autour d’une base de données corrompue.

La commande finale tar -tzf affiche ce qui a réellement été capturé. Lisez cette sortie lors de la première exécution. Vous devez trouver ./db.sqlite3, ./rsa_key.pem, ./config.json et ./attachments/, et constater l’absence de ./db.sqlite3-wal. Exécutez le script chaque nuit avec un service et un timer systemd plutôt qu’avec cron si vous voulez une sortie journalctl et une unité qui signale les échecs.

Vérifiez la sauvegarde en la restaurant dans un répertoire de travail

Une sauvegarde qui n’a pas été testée reste une supposition. La restaurer dans un répertoire de travail prend une minute et ne modifie rien en production.

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

Quatre résultats sont importants. integrity_check affiche ok. Le nombre d’utilisateurs correspond au nombre de comptes que vous connaissez. Le nombre de chiffrements est proche de la valeur observée sur le système actif avec sudo sqlite3 /opt/vaultwarden/data/db.sqlite3 "select count(*) from ciphers;", et il n’est jamais nul sur un coffre utilisé. Le répertoire des pièces jointes a approximativement la taille attendue. Vous pouvez ignorer ce contrôle si personne n’envoie de pièces jointes. Exécutez ensuite sudo rm -rf /tmp/vw-check, car ce répertoire contient désormais une deuxième copie de toutes les données.

Lorsque vous restaurez un dossier de données copié manuellement, supprimez toujours db.sqlite3-wal et db.sqlite3-shm avant de démarrer le serveur. Sinon, SQLite tentera de récupérer la base de données restaurée avec un journal appartenant à une autre copie. Cela corrompt une base de données qui était intacte lors de sa restauration. Les archives produites par le script précédent ne contiennent jamais ces fichiers, car .backup écrit une base de données complète.

Restaurer sur le serveur

Exécutez ces commandes sur votre propre serveur, avec le conteneur arrêté. Vaultwarden ne doit pas écrire dans le dossier de données pendant que son contenu est modifié.

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

Le chown doit indiquer l’utilisateur sous lequel le conteneur s’exécute. L’image standard s’exécute avec root. root:root convient donc, sauf si vous avez défini user: dans votre fichier compose. Dans ce cas, utilisez l’uid et le gid correspondants. Si le serveur ne peut pas écrire dans le dossier de données, la page de connexion s’affiche, mais chaque requête échoue. Les journaux l’indiquent.

Un démarrage correct se termine par la ligne Rocket suivante :

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

Connectez-vous ensuite depuis un navigateur, ouvrez un élément et téléchargez une pièce jointe. Si la connexion fonctionne, mais que les téléchargements de pièces jointes échouent, l’archive contient la base de données, mais pas attachments/. Conservez data.old.* jusqu’à ce que tous ces contrôles soient terminés, puis supprimez-le. Pour revenir en arrière, suivez les mêmes trois étapes en inversant les répertoires.

Si vos chemins ne correspondent pas à ceux indiqués ici, le guide d’installation de Vaultwarden sur un VPS présente le fichier compose utilisé par ces commandes.

Où ne pas stocker la sauvegarde

  • Pas sur le même disque que le dossier de données. Un volume défaillant détruit les deux copies, tout comme un rm -rf sur le mauvais chemin.
  • Pas sur le même serveur, même sur un second volume. Un attaquant qui obtient root accède à vos sauvegardes au cours de la même session.
  • Pas dans un stockage objet sans chiffrement, car l’archive contient des adresses e-mail, des indications de mot de passe, des codes de récupération et du ciphertext de coffre-fort qui peuvent être attaqués hors ligne.
  • Ne comptez pas uniquement sur les snapshots de votre fournisseur. Leur restauration est rapide, ce qui est utile, mais ils se trouvent dans le même compte que le serveur. Un problème de compte les affecte donc également.

Une copie hors site est le cas d’usage de restic, car un repository restic est chiffré sur la machine avant tout upload. Sur votre serveur :

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

Indiquez à restic le répertoire d’archive, et non le dossier de données actif, afin qu’il uploade la copie cohérente que vous avez déjà vérifiée. Conservez le mot de passe du repository ailleurs que sur le serveur qu’il protège : si vous perdez ce mot de passe, les snapshots sont illisibles, conformément à la conception du système. Lorsque le stockage le permet, donnez au serveur des identifiants qui autorisent l’écriture, mais pas la suppression. Ainsi, la compromission de la machine ne peut pas effacer son propre historique. Configurer des sauvegardes restic sur un VPS décrit en détail le repository et la planification. restic comparé à BorgBackup présente les critères de choix si vous ne vous êtes pas encore décidé.

Tester la restauration selon un calendrier

Choisissez un jour par mois. Récupérez le snapshot le plus récent dans un répertoire de travail avec restic restore latest --tag vaultwarden --target /tmp/vw-check, exécutez le même PRAGMA integrity_check, vérifiez les mêmes nombres de lignes, puis notez la date et les nombres. Une sauvegarde qui n’a pas été restaurée depuis six mois est une sauvegarde dont l’état est inconnu. Vous découvrirez son état pendant une panne, au pire moment pour le découvrir.

Une fois par an, effectuez la procédure complète. Démarrez un second conteneur Vaultwarden sur un port libre avec le dossier de données restauré, puis connectez-vous avec un compte réel. Cela valide le fonctionnement du mot de passe maître de bout en bout, ce qu’aucun nombre de lignes ne peut faire. restic check --read-data-subset=10% selon le même calendrier vérifie que les données stockées sont lisibles et pas seulement listées.

FAQ

Puis-je copier db.sqlite3 avec cp pendant que Vaultwarden fonctionne ?

Non. Vaultwarden utilise SQLite en mode WAL. Les écritures récentes se trouvent donc dans db.sqlite3-wal et ne sont pas encore présentes dans db.sqlite3. Une cp du fichier principal seul les perd silencieusement. Copier les deux fichiers séparément peut aussi produire une paire incohérente, qui provoquera plus tard une Error: database disk image is malformed. Utilisez plutôt sqlite3 /path/db.sqlite3 ".backup '/path/out.sqlite3'". Cette commande utilise l’Online Backup API de SQLite et produit un fichier cohérent pendant que le serveur continue de répondre aux requêtes.

Dois-je arrêter le conteneur Vaultwarden pour effectuer une sauvegarde ?

Non, c’est précisément l’objectif de .backup. La copie de la base de données est sûre sur un serveur en fonctionnement. Les pièces jointes et les fichiers Send sont écrits lorsqu’un utilisateur en envoie un. Un fichier ajouté entre la copie de la base de données et le tar peut donc manquer dans l’archive de cette nuit. Dans le pire des cas, vous perdez une pièce jointe. Si quelques secondes d’interruption ne vous gênent pas, docker compose stop avant le script et docker compose start après celui-ci éliminent aussi ce risque.

Que se passe-t-il si je restaure les données sans les fichiers rsa_key ?

Vaultwarden génère une nouvelle clé au démarrage. Cette clé signe les JSON Web Tokens (JWT) qui maintiennent les sessions actives. Tous les tokens existants cessent donc d’être valides, et tous les clients sont déconnectés. Ils doivent se reconnecter. Le contenu du coffre n’est pas affecté, car il est chiffré avec des clés dérivées du mot de passe maître de chaque utilisateur, et non avec la clé RSA. Restaurez rsa_key.pem avec le reste du dossier de données pour que personne ne remarque la restauration.

L’archive de sauvegarde peut-elle être envoyée telle quelle vers un object storage ?

Non. Les noms des éléments, les mots de passe et les notes sont chiffrés. En revanche, les adresses e-mail, les noms de compte, les aides-mémoire de mots de passe et les codes de récupération de l’authentification à deux facteurs sont en clair dans la base de données. Un attaquant hors ligne peut aussi tester le ciphertext à son propre rythme. Chiffrez l’archive avant qu’elle ne quitte la machine. Un repository restic s’en charge, et gpg --symmetric --cipher-algo AES256 vw-20260805-030000.tar.gz produit un fichier chiffré unique que vous pouvez transmettre à n’importe quel stockage.

Comment sauvegarder Vaultwarden avec PostgreSQL ou MariaDB ?

Les étapes pour SQLite ne s’appliquent pas. La commande intégrée refuse également de fonctionner avec The database type is not SQLite. Backups only works for SQLite databases. Exportez la base de données avec son outil natif, pg_dump ou mysqldump, et conservez toutes les autres règles. Le dump doit se trouver dans une seule archive avec attachments/, sends/, config.json et les fichiers rsa_key. Effectuez ces opérations dans la même exécution, chiffrez l’archive et stockez-la ailleurs que sur le serveur qui l’a créée.