SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-24

Como fazer backup e restaurar o Vaultwarden

Use sqlite3 .backup para copiar o Vaultwarden em execução. Preserve attachments, config.json e rsa_key, e teste a restauração antes de precisar dela.

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

O que um backup do Vaultwarden deve conter

Um backup do Vaultwarden é uma cópia de toda a pasta de dados, e a base de dados que está dentro dela tem de ser copiada da forma correta. Execute sqlite3 db.sqlite3 ".backup out.sqlite3" em vez de cp, porque uma cópia simples de uma base de dados que está a ser escrita pode resultar num ficheiro que não abre. Depois, mantenha os ficheiros que ficam ao lado dela. Esta é a parte que muitas pessoas esquecem.

Numa instalação Docker, a pasta de dados é o local que montou em /data. Pode ser um caminho no host ou um volume nomeado, e a diferença entre bind mounts e volumes nomeados determina onde o seu cofre está realmente armazenado no disco. É isto que a pasta contém.

  • db.sqlite3: todas as contas, todos os itens do cofre, todas as pastas e todas as organizações. Perder este ficheiro significa perder o cofre.
  • db.sqlite3-wal e db.sqlite3-shm: o write-ahead log (WAL) e o respetivo índice de memória partilhada. As escritas recentes ficam aqui até o SQLite as integrar no ficheiro principal.
  • attachments/: os ficheiros anexados pelos utilizadores aos itens do cofre, encriptados, num diretório por item.
  • sends/: os ficheiros associados às ligações do Bitwarden Send.
  • config.json: todas as definições guardadas na página de administração.
  • rsa_key.pem, além de rsa_key.der e rsa_key.pub.der em instalações mais antigas: a chave que assina os tokens de início de sessão.
  • icon_cache/: ícones de sites transferidos. Este é o único diretório que pode ignorar, porque o Vaultwarden volta a transferi-los quando necessário.

A minha base de dados do Vaultwarden está segura? O que o ficheiro contém realmente

Duas comandas respondem a essa pergunta e pode executar ambas agora.

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

A primeira mostra os endereços de e-mail dos seus utilizadores em texto simples. A segunda mostra o nome de um item, com este aspeto:

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

Os nomes dos itens, nomes de utilizador, palavras-passe e notas são cifrados pelo cliente antes de serem enviados. Por isso, o servidor armazena texto cifrado que não consegue ler. O prefixo 2. identifica o tipo de cifragem do Bitwarden. Depois dele vêm o vetor de inicialização (IV), o texto cifrado e um MAC (código de autenticação de mensagem), todos em base64 e separados por |. A chave que o decifra é derivada da palavra-passe principal da conta, que nunca chega ao servidor numa forma utilizável. Esta parte é igual quer execute o Vaultwarden quer o servidor oficial, como explica a comparação entre o Vaultwarden e o Bitwarden autoalojado.

O resto da base de dados não é cifrado. Os endereços de e-mail, nomes das contas, sugestões de palavras-passe e códigos de recuperação da autenticação de dois fatores são armazenados em texto simples, juntamente com metadados como as datas de criação e a organização proprietária de um item. Por isso, o ficheiro de backup é, por si só, um segredo. Qualquer pessoa que o obtenha fica a saber quem são os seus utilizadores e pode atacar os blobs cifrados offline à velocidade permitida pelo seu hardware. Este facto determina as regras de armazenamento apresentadas mais abaixo: a cópia é cifrada antes de sair do servidor. O token de administrador é a outra parte do mesmo problema, e o reforço de segurança de um Vaultwarden autoalojado trata ambos.

Por que copiar db.sqlite3 enquanto o Vaultwarden está em execução não é um backup

Por padrão, o Vaultwarden executa o SQLite no modo WAL (ENABLE_DB_WAL=true). Uma operação de escrita é gravada primeiro em db.sqlite3-wal. Só um checkpoint a incorpora em db.sqlite3. Se copiar apenas db.sqlite3, obterá a base de dados no estado do último checkpoint. Uma palavra-passe guardada há dez minutos pode não estar no seu arquivo, sem qualquer aviso.

Copiar os três ficheiros com cp também não resolve. As cópias são feitas em momentos ligeiramente diferentes. Por isso, o WAL guardado pode descrever versões de páginas que já não correspondem ao ficheiro principal guardado. O SQLite recupera um ficheiro a partir do outro, e o resultado fica incorreto. Só descobrirá isso muito mais tarde:

Error: database disk image is malformed

.backup evita este problema porque usa a Online Backup API do SQLite. A documentação do SQLite indica-a como o método adequado para copiar uma base de dados que pode estar em uso. A API lê as páginas sob um bloqueio de leitura e recomeça se um processo de escrita alterar o ficheiro durante a operação. Assim, o que fica gravado no disco representa um único estado consistente.

Faça a cópia da base de dados com 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;"

O último comando imprime ok numa linha própria. Qualquer outro resultado significa que a cópia não é utilizável. Não a mantenha nem elimine a cópia anterior. Toda a sequência é executada num servidor ativo. Ninguém termina a sessão e nenhum contentor é reiniciado.

A ferramenta sqlite3 não está dentro do contentor Vaultwarden. A imagem é baseada em debian:trixie-slim com ca-certificates, curl, libmariadb3, libpq5 e openssl. Por isso, docker exec vaultwarden sqlite3 ... falha com:

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

Execute-a no host contra o caminho montado. É isso que os comandos acima fazem. Se os dados estiverem num volume nomeado, docker volume inspect <name> mostra o caminho no host em /var/lib/docker/volumes/.

O Vaultwarden também inclui o seu próprio comando de backup desde a versão 1.32.1. No servidor:

docker exec -it vaultwarden /vaultwarden backup

O comando executa VACUUM INTO e grava db_YYYYMMDD_HHMMSS.sqlite3 na pasta de dados. Há duas consequências. A cópia fica junto do original no mesmo disco. É, portanto, uma etapa de preparação, não um backup. Além disso, funciona apenas com SQLite. Em MariaDB ou PostgreSQL, termina com The database type is not SQLite. Backups only works for SQLite databases.

Os ficheiros que as pessoas esquecem

attachments/ contém texto cifrado com nomes opacos. A linha da base de dados de cada anexo contém o nome de ficheiro cifrado e o material de chave de que um cliente precisa para decifrar o ficheiro. Os anexos sem a base de dados são dados ilegíveis, e uma base de dados sem os anexos apresenta aos utilizadores itens cujos downloads falham. Inclua ambos na mesma execução.

config.json contém tudo o que guardou na página de administração, e os respetivos valores têm precedência sobre as variáveis de ambiente correspondentes. Isto pode causar problemas nos dois sentidos: restaurar um config.json antigo substitui silenciosamente as definições do seu ficheiro compose, e o próprio ficheiro é sensível porque pode conter a palavra-passe SMTP e o token de administração. Armazene esse token como uma string PHC Argon2id (password hashing competition), em vez de texto simples. docker run --rm -it vaultwarden/server /vaultwarden hash gera uma string para si.

rsa_key.pem assina os JSON Web Tokens (JWT) que mantêm os clientes autenticados. Se o ficheiro não existir no arranque, o Vaultwarden gera uma chave nova. Por isso, todos os tokens assinados pela chave antiga deixam de ser válidos e todos os clientes terminam a sessão. O conteúdo do Vault não é afetado, porque é cifrado com chaves derivadas da palavra-passe principal. Restaurar o ficheiro da chave evita o encerramento generalizado das sessões.

sends/ contém os ficheiros disponibilizados através das ligações Send. A ausência desses ficheiros interrompe esses downloads, mas não afeta mais nada.

Coloque tudo num único 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"

Guarde-o como /usr/local/sbin/vw-backup.sh, torne-o executável com chmod 700 e execute-o como root. A linha test faz trabalho efetivo: sqlite3 termina com o código 0 mesmo quando PRAGMA integrity_check comunica corrupção. Por isso, comparar a saída com ok é o que transforma uma cópia inválida numa falha do script. Em seguida, set -euo pipefail interrompe tudo, em vez de permitir que tar crie um arquivo organizado em torno de uma base de dados danificada.

O tar -tzf final apresenta o que foi realmente capturado. Leia essa saída na primeira execução. Procure ./db.sqlite3, ./rsa_key.pem, ./config.json e ./attachments/, e confirme a ausência de ./db.sqlite3-wal. Execute o script todas as noites com um serviço e um temporizador do systemd em vez de cron se quiser uma saída de journalctl e uma unidade que comunique falhas.

Verifique o backup restaurando-o num diretório temporário

Um backup não testado é apenas uma suposição. Restaurá-lo num diretório temporário demora um minuto e não altera nada em produção.

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

Há quatro resultados importantes. integrity_check imprime ok. A contagem de utilizadores corresponde ao número de contas que conhece. A contagem de cifras é próxima do valor em produção apresentado por sudo sqlite3 /opt/vaultwarden/data/db.sqlite3 "select count(*) from ciphers;" e nunca é zero num cofre em utilização. O diretório de anexos tem aproximadamente o tamanho esperado. Pode ignorá-lo se ninguém carregar anexos. Em seguida, execute sudo rm -rf /tmp/vw-check, porque esse diretório contém agora uma segunda cópia de tudo.

Ao restaurar qualquer diretório de dados copiado manualmente, elimine db.sqlite3-wal e db.sqlite3-shm antes de iniciar o servidor. Caso contrário, o SQLite tentará recuperar a base de dados restaurada usando um log pertencente a outra cópia. Isso corrompe uma base de dados que estava intacta. Os arquivos produzidos pelo script acima nunca contêm esses ficheiros, porque .backup grava uma base de dados completa.

Restaurar no servidor

Execute estes comandos no seu próprio servidor, com o contentor parado. O Vaultwarden não pode estar a escrever enquanto a pasta de dados é alterada.

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

O chown tem de indicar o utilizador com que o contentor é executado. A imagem padrão é executada como root, portanto root:root está correto, a menos que tenha definido user: no seu ficheiro compose. Nesse caso, use esse uid e gid. Se o servidor não conseguir escrever na pasta de dados, a página de início de sessão falhará em todos os pedidos. Os logs indicam essa causa.

Um arranque saudável termina com a linha Rocket:

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

Em seguida, inicie sessão num navegador, abra um item e descarregue um anexo. Se o início de sessão funcionar, mas os downloads de anexos falharem, o arquivo continha a base de dados, mas não attachments/. Mantenha data.old.* até confirmar que tudo funciona. Depois, elimine-o. Para reverter, execute os mesmos três passos, trocando os diretórios entre si.

Se os seus caminhos não corresponderem aos apresentados aqui, o guia de instalação do Vaultwarden para um VPS mostra o ficheiro compose que estes comandos pressupõem.

Onde não guardar o backup

  • Não o guarde no mesmo disco que a pasta de dados. Uma falha de volume elimina as duas cópias, tal como um rm -rf no caminho errado.
  • Não o guarde no mesmo servidor, mesmo num segundo volume. Um atacante que obtenha acesso a root também acede aos backups na mesma sessão.
  • Não o guarde em object storage sem encriptação, porque o arquivo contém endereços de email, sugestões de palavras-passe, códigos de recuperação e texto cifrado do cofre que podem ser atacados offline.
  • Não dependa apenas dos snapshots do seu fornecedor. A restauração é rápida, o que é útil, mas os snapshots ficam na mesma conta que o servidor. Um problema na conta também os elimina.

Uma cópia externa é o caso de uso do restic, porque um repositório restic é encriptado na máquina antes de qualquer carregamento. No servidor:

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

Aponte o restic para o diretório do arquivo e não para a pasta de dados ativa, para que o que é carregado seja a cópia consistente que já verificou. Guarde a palavra-passe do repositório noutro local que não seja o servidor que ele protege: se perder essa palavra-passe, os snapshots ficam ilegíveis, por conceção. Quando o armazenamento o permitir, atribua ao servidor credenciais que possam escrever, mas não apagar, para que um comprometimento do servidor não possa eliminar o seu próprio histórico. Configurar backups do restic num VPS explica completamente o repositório e o agendamento, e restic comparado com BorgBackup aborda a escolha, caso ainda não a tenha feito.

Teste a restauração regularmente

Escolha um dia por mês. Extraia o snapshot mais recente para um diretório temporário com restic restore latest --tag vaultwarden --target /tmp/vw-check, execute o mesmo PRAGMA integrity_check, repita as contagens de linhas e registe a data e as contagens. Um backup que ninguém restaurou durante seis meses tem um estado desconhecido. O estado só será conhecido durante uma indisponibilidade, que é o pior momento para o descobrir.

Uma vez por ano, faça o teste completo. Inicie um segundo container Vaultwarden numa porta livre, usando a pasta de dados restaurada, e inicie sessão com uma conta real. Isto comprova o funcionamento do percurso da palavra-passe principal de ponta a ponta, algo que nenhuma contagem de linhas consegue fazer. restic check --read-data-subset=10% com a mesma periodicidade confirma que os dados armazenados podem ser lidos, em vez de apenas listados.

FAQ

Posso copiar db.sqlite3 com cp enquanto o Vaultwarden está em execução?

Não. O Vaultwarden usa o SQLite no modo WAL, por isso as gravações recentes ficam em db.sqlite3-wal e ainda não estão em db.sqlite3. Uma cp apenas do ficheiro principal perde-as silenciosamente, e copiar os dois ficheiros separadamente pode deixar um par inconsistente que mais tarde aparece como Error: database disk image is malformed. Use sqlite3 /path/db.sqlite3 ".backup '/path/out.sqlite3'". Este comando usa a Online Backup API do SQLite e produz um ficheiro consistente enquanto o servidor continua a servir pedidos.

Tenho de parar o contentor Vaultwarden para fazer uma cópia de segurança?

Não, e esse é precisamente o objetivo de .backup. A cópia da base de dados é segura num servidor em execução. Os anexos e os ficheiros Send são gravados quando um utilizador faz um upload, por isso um ficheiro adicionado entre a cópia da base de dados e o tar pode ficar de fora do arquivo dessa noite. No pior caso, perde um anexo. Se alguns segundos de indisponibilidade não forem um problema, docker compose stop antes do script e docker compose start depois dele elimina até esse risco.

O que acontece se eu restaurar sem os ficheiros rsa_key?

O Vaultwarden gera uma nova chave no arranque. Essa chave assina os JSON Web Tokens (JWT) que mantêm as sessões ativas, por isso todos os tokens existentes deixam de ser válidos e todos os clientes terminam a sessão e têm de iniciar sessão novamente. O conteúdo do cofre não é afetado, porque é cifrado com chaves derivadas da palavra-passe principal de cada utilizador, e não com a chave RSA. Restaure rsa_key.pem juntamente com o restante diretório de dados e ninguém notará a restauração.

O arquivo de cópia de segurança é seguro para carregar para o armazenamento de objetos tal como está?

Não. Os nomes dos itens, as palavras-passe e as notas são texto cifrado, mas os endereços de e-mail, os nomes das contas, as sugestões de palavras-passe e os códigos de recuperação da autenticação de dois fatores estão em texto simples na base de dados. Além disso, um atacante offline pode tentar decifrar o texto cifrado ao seu próprio ritmo. Cifre o arquivo antes de este sair da máquina. Um repositório restic faz isso por si, e gpg --symmetric --cipher-algo AES256 vw-20260805-030000.tar.gz produz um único ficheiro cifrado que pode entregar a qualquer armazenamento.

Como faço uma cópia de segurança do Vaultwarden em PostgreSQL ou MariaDB?

Os passos para SQLite não se aplicam, e o comando incorporado recusa a operação com The database type is not SQLite. Backups only works for SQLite databases. Faça um dump da base de dados com a ferramenta nativa correspondente, pg_dump ou mysqldump, e mantenha todas as restantes regras. O dump deve ficar num único arquivo com attachments/, sends/, config.json e os ficheiros rsa_key. Faça tudo na mesma execução, cifre o arquivo e armazene-o noutro local que não seja o servidor que o criou.