Kopia zapasowa Vaultwarden: eksport Bitwarden CLI do szyfrowanego 7z

Kopia zapasowa Vaultwarden robiona ręcznie wyglądała u mnie zawsze tak samo. W każdą sobotę logowałem się do sejfu w przeglądarce, eksportowałem dwa pliki CSV i pakowałem je do archiwum 7z z hasłem. To działa, ale tylko wtedy, gdy o tym pamiętasz. Dlatego przeniosłem cały proces do terminala.
Poniżej opisuję rozwiązanie, którego używam w domowej sieci. Bitwarden CLI eksportuje sejf osobisty i organizację, a krótki skrypt pakuje oba pliki do zaszyfrowanego archiwum. Ten sam skrypt uruchomisz na Linuksie i na macOS.
Stan informacji i wersji: 31 października 2026 r. Bitwarden CLI 2026.10.0, Ubuntu 22.04 oraz macOS z Homebrew.
W skrócie: najpierw
bw sync, potembw exportdla sejfu osobistego i organizacji, na końcu7zz hasłem wpisywanym z klawiatury i zaszyfrowaną listą plików. Pliki CSV znikają zaraz po spakowaniu.
W artykule:
- Punkt wyjścia: ręczny eksport co tydzień
- Instalacja Bitwarden CLI i pułapka z npm
- Konfiguracja i pierwszy eksport
- Skrypt do szyfrowanego 7z
- Ten sam skrypt na macOS
- Czego nie zawiera eksport CSV
- Najczęstsze pytania
Kopia zapasowa Vaultwarden: punkt wyjścia
Na serwerze Vaultwarden trzymam dwa zbiory haseł: sejf osobisty oraz organizację współdzieloną z zespołem. W panelu webowym oba wybieram z listy źródeł eksportu. Sejf osobisty widnieje tam jako „My vault”, a organizacja pod własną nazwą.
Każdy eksport trafia do osobnego pliku CSV. Następnie oba pliki pakuję do archiwum 7z z hasłem. Nazwa archiwum zawiera datę w formacie RR_MM_DD:
26_09_26_VW.7z
26_10_03_VW.7z
26_10_10_VW.7z
26_10_17_VW.7z
Ten układ chciałem zachować. Zmienić miał się tylko sposób tworzenia kopii: zamiast kilkunastu kliknięć jedno polecenie.
Instalacja Bitwarden CLI
Vaultwarden implementuje API Bitwardena. Dzięki temu współpracuje z oficjalnymi klientami, w tym z narzędziem wiersza poleceń bw. Eksport odbywa się po stronie klienta. CLI pobiera zaszyfrowany sejf i odszyfrowuje go lokalnie, więc otwarte dane nie przechodzą przez sieć.
Pułapka, na której się przejechałem: npm i stary Node.js
Pierwszy odruch to instalacja przez npm. Na Ubuntu 22.04 kończy się ona jednak serią ostrzeżeń i błędem:
$ npm install -g @bitwarden/cli
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE package: '@bitwarden/cli@2026.10.0',
npm WARN EBADENGINE required: { npm: '>=10', node: '>=22' },
npm WARN EBADENGINE current: { node: 'v12.22.9', npm: '8.5.1' }
...
npm ERR! code EACCES
npm ERR! path /usr/local/lib/node_modules
Widać tu dwa niezależne problemy. Błąd EACCES wynika z instalacji globalnej bez uprawnień roota. Ważniejsze są jednak ostrzeżenia EBADENGINE. Aktualne wydanie CLI wymaga Node.js 22, a Ubuntu 22.04 dostarcza wersję 12. Dlatego sudo niczego tu nie naprawi.
Zamiast aktualizować Node.js, wybrałem natywną binarkę. Jest samodzielna i nie potrzebuje żadnego środowiska uruchomieniowego:
cd /tmp
wget -O bw.zip \
"https://vault.bitwarden.com/download/?app=cli&platform=linux"
unzip bw.zip
sudo install -m 755 bw /usr/local/bin/bw
bw --version
Bez uprawnień administratora skopiuj plik do ~/.local/bin. Po ponownym zalogowaniu Ubuntu doda ten katalog do zmiennej PATH.
Nieudana instalacja npm nie zostawia nic w katalogach systemowych. W katalogu domowym zostają jedynie cache i logi:
rm -rf ~/.npm
Jeżeli Node.js był potrzebny tylko do tego celu, usuń go razem z zależnościami. Przed potwierdzeniem przejrzyj listę pakietów, którą pokaże apt:
sudo apt purge nodejs npm
sudo apt autoremove --purge
Konfiguracja Bitwarden CLI dla Vaultwarden
Krok 1: adres serwera
bw config server https://vault.twoja-domena.pl
Jeśli serwer używa certyfikatu z własnego CA, wskaż plik tego CA w zmiennej NODE_EXTRA_CA_CERTS. Zrób to przed pierwszym połączeniem.
Krok 2: logowanie kluczem API
Logowanie nazwą użytkownika i hasłem działa, ale przy włączonym 2FA wymaga kodu. Z tego powodu wybrałem klucz API konta. Znajdziesz go w panelu webowym: Ustawienia konta → Bezpieczeństwo → Klucze → Wyświetl klucz API.
bw login --apikey
Polecenie zapyta o client_id i client_secret. Klucz API loguje jednak tylko do konta. Do odszyfrowania sejfu nadal potrzebne jest hasło główne.
Krok 3: odblokowanie sejfu i identyfikator organizacji
export BW_SESSION=$(bw unlock --raw)
bw list organizations --pretty
Pierwsze polecenie pyta o hasło główne i zapisuje klucz sesji w zmiennej. Drugie wyświetla organizacje. Zanotuj wartość pola id właściwej organizacji.
Krok 4: testowy eksport
bw export --format csv --output osobisty.csv
bw export --organizationid TU_WSTAW_ID_ORGANIZACJI \
--format csv --output organizacja.csv
Pierwsze polecenie eksportuje wyłącznie sejf osobisty. Dane organizacji wymagają osobnego eksportu z parametrem --organizationid. Oba pliki zawierają hasła otwartym tekstem, więc po teście usuń je poleceniem shred -u.
Skrypt: kopia zapasowa Vaultwarden do szyfrowanego 7z
Skrypt umieszczam w katalogu z kopiami. Uruchamiam go ręcznie, ponieważ pyta o dwa hasła: główne do sejfu oraz hasło archiwum. Żadnego z nich nie przechowuję na dysku. Przed użyciem wpisz identyfikator swojej organizacji w zmiennej ORG_ID.
#!/usr/bin/env bash
# vw-backup.sh – eksport Vaultwarden (sejf osobisty
# + organizacja) do szyfrowanego 7z RR_MM_DD_VW.7z
# Działa na Linuksie i macOS.
set -euo pipefail
umask 077
cd "$(dirname "$0")"
ORG_ID="TU_WSTAW_ID_ORGANIZACJI"
ARCHIVE="$(date +%y_%m_%d)_VW.7z"
FILES=(osobisty.csv organizacja.csv)
# 7z (Linux, p7zip) albo 7zz (macOS, brew sevenzip)
SEVENZ="$(command -v 7z || command -v 7zz)" || {
echo "Brak 7z/7zz w PATH." >&2
exit 1
}
# shred na Linuksie, rm na macOS (brak shred,
# a na APFS nadpisywanie i tak nic nie daje)
wipe() {
if command -v shred >/dev/null 2>&1; then
shred -u -- "$@" 2>/dev/null || true
else
rm -f -- "$@"
fi
}
cleanup() {
wipe "${FILES[@]}"
bw lock >/dev/null 2>&1 || true
}
trap cleanup EXIT
if [[ -e $ARCHIVE ]]; then
echo "Plik $ARCHIVE już istnieje – przerywam." >&2
exit 1
fi
# resztki po poprzednim uruchomieniu
wipe "${FILES[@]}"
# pyta o hasło główne
BW_SESSION="$(bw unlock --raw)"
export BW_SESSION
# bez sync eksport może być z nieaktualnego cache
bw sync >/dev/null
bw export --format csv --output osobisty.csv
bw export --organizationid "$ORG_ID" \
--format csv --output organizacja.csv
# -p bez wartości: 7z pyta o hasło (nie trafia
# do historii ani ps); -mhe=on szyfruje listę plików
"$SEVENZ" a -t7z -mhe=on -p "$ARCHIVE" "${FILES[@]}"
echo "OK: $ARCHIVE"
Uruchomienie:
chmod 700 vw-backup.sh
./vw-backup.sh
Co robi skrypt i dlaczego
umask 077sprawia, że pliki CSV i archiwum powstają z prawami 600.trap cleanup EXITusuwa pliki CSV i blokuje sejf również wtedy, gdy któryś krok zakończy się błędem.- Kontrola nazwy archiwum chroni przed dopisaniem plików do kopii z tego samego dnia.
- Osobne przypisanie
BW_SESSIONma znaczenie przyset -e. W wariancieexport BW_SESSION=$(...)błędne hasło nie przerwałoby skryptu. bw syncpobiera aktualny stan sejfu. CLI pracuje na lokalnej kopii danych, więc bez synchronizacji eksport może pominąć zmiany wprowadzone w przeglądarce lub na telefonie.-pbez wartości powoduje, że 7z sam pyta o hasło. Hasło nie trafia więc do historii powłoki ani do listy procesów.-mhe=onszyfruje nagłówki archiwum. Bez hasła nie zobaczysz nawet nazw plików.
Na koniec sprawdź wynik:
7z l 26_10_31_VW.7z
7z powinien najpierw zapytać o hasło, a dopiero potem pokazać oba pliki.
Uwaga:
shrednadpisuje plik, ale na dyskach SSD nie gwarantuje fizycznego usunięcia danych. Realną ochroną pozostaje szyfrowanie całego dysku. Pliki CSV istnieją tylko przez kilka sekund między eksportem a pakowaniem.
Kopia zapasowa Vaultwarden na macOS
Pierwsza wersja skryptu nie działała na Macu. Zawiodły trzy elementy: macOS nie ma polecenia shred, Homebrew instaluje 7-Zip jako 7zz, a starsze wersje systemu nie obsługują readlink -f. Wersja powyżej uwzględnia wszystkie trzy różnice.
Przed pierwszym uruchomieniem zainstaluj narzędzia i skonfiguruj CLI. Konfiguracja z innego komputera nie przenosi się automatycznie:
brew install bitwarden-cli sevenzip
bw config server https://vault.twoja-domena.pl
bw login --apikey
Na macOS skrypt usuwa pliki CSV zwykłym rm. Na dysku APFS nadpisywanie i tak niczego nie gwarantuje. Dlatego upewnij się, że FileVault jest włączony.
Czego nie zawiera eksport CSV
Format CSV jest wygodny, ale niekompletny. Według dokumentacji Bitwardena karty płatnicze, tożsamości, passkeys i klucze SSH trafiają wyłącznie do eksportu JSON. Ponadto eksporty CSV i JSON nie obejmują załączników, kosza ani elementów Send.
Jeżeli kopia zapasowa Vaultwarden ma obejmować te typy danych, zmień w skrypcie format na JSON. Archiwum 7z i tak szyfruje zawartość, więc opcja encrypted_json nie jest tu potrzebna:
bw export --format json --output osobisty.json
bw export --organizationid "$ORG_ID" \
--format json --output organizacja.json
Pamiętaj wtedy o zmianie nazw plików w tablicy FILES.
Załączniki sejfu osobistego Bitwarden pozwala pobrać w aplikacji webowej jako eksport .zip. Sprawdź, czy ta opcja jest dostępna w Twojej wersji panelu Vaultwarden.
Eksport to nie wszystko: kopia danych serwera
Kopia zapasowa Vaultwarden wykonana przez CLI chroni zawartość sejfów. Nie zastępuje jednak kopii samego serwera. Do odtworzenia całej instancji potrzebny jest katalog danych Vaultwarden: baza db.sqlite3, katalogi attachments i sends, klucze rsa_key* oraz plik config.json, jeśli istnieje. Działającą bazę kopiuj poleceniem sqlite3 db.sqlite3 ".backup kopia.sqlite3", a nie zwykłym cp. Szczegóły opisuje wiki projektu.
Najczęstsze pytania
Czy skrypt może działać z crona bez podawania haseł?
Technicznie tak. CLI przyjmuje hasło główne z pliku lub ze zmiennej środowiskowej (bw unlock --passwordfile, --passwordenv). Hasło archiwum trzeba by jednak również zapisać na dysku. Wtedy oba sekrety leżą obok kopii, którą mają chronić. Dlatego świadomie zostałem przy trybie interaktywnym.
Czy eksport organizacji wymaga specjalnych uprawnień?
Tak. Konto musi mieć prawo eksportu danych organizacji, zwykle rolę właściciela lub administratora. Bez tego drugie polecenie bw export zakończy się błędem.
Gdzie trzymać hasło do archiwum?
Poza sejfem, którego kopię chroni. Jeśli hasło archiwum zapiszesz tylko w Vaultwarden, po awarii serwera nie otworzysz żadnej kopii. Użyj długiego, unikalnego hasła i przechowuj je niezależnie, na przykład na papierze w bezpiecznym miejscu.
Podsumowanie
Kopia zapasowa Vaultwarden to teraz jedno polecenie i dwa hasła. Skrypt synchronizuje sejf, eksportuje dane, pakuje je do szyfrowanego archiwum i sprząta po sobie. Nazwy archiwów pozostały takie same, więc nowe kopie leżą obok starych.
A Ty jak zabezpieczasz kopię swojego sejfu haseł? Podziel się doświadczeniami w komentarzu.
Powiązane wpisy
Dokumentacja
- Bitwarden: Password Manager CLI
- Bitwarden: eksport danych sejfu
- Bitwarden: eksport zaszyfrowany
- Vaultwarden wiki: Backing up your vault
G
Tagi: kopie zapasowe, linia poleceń, Linux, Mac OS, Vaultwarden