Vaultwarden — свой Bitwarden
Пользовался Bitwarden Cloud полтора года, претензий не было. Решил всё-таки переехать к себе — больше из принципа, чем по реальной необходимости. Vaultwarden — совместимая с Bitwarden реализация на Rust, лёгкая, влезает в 100 MB RAM. Клиенты те же: расширения для браузеров, мобильные приложения, всё работает без правок.
compose.yml
Структура папки — как в прошлом посте (один сервис = одна папка):
services:
app:
image: vaultwarden/server:1.32.5
container_name: vaultwarden
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
env_file: .env
volumes:
- ./data:/data
В .env лежит то, что не хочу хардкодить в compose:
DOMAIN=https://vault.myhome.example
SIGNUPS_ALLOWED=false
ADMIN_TOKEN=<argon2-хеш>
PUSH_ENABLED=false
SHOW_PASSWORD_HINT=false
SIGNUPS_ALLOWED=false
Vaultwarden по умолчанию открыт: любой, кто попадёт на URL, создаёт себе аккаунт. На публичном домене это плохая идея. Сначала зарегался сам, потом сразу выключил регистрацию.
Если в будущем понадобится добавить пользователя, есть INVITATIONS_ALLOWED — приглашение по ссылке, без открытой регистрации.
ADMIN_TOKEN — обязательно argon2-хеш
В Vaultwarden есть /admin UI для диагностики и управления. Доступ — по ADMIN_TOKEN.
В старых версиях ADMIN_TOKEN задавался plain-строкой. Если .env утёк — у злоумышленника сразу админка. С 1.30 поддерживается argon2:
echo -n 'мой-секрет-админа' | argon2 \
"$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4
В .env идёт хешированное значение. Plain секрет лежит у меня же в Vaultwarden — рекурсивно, да.
DOMAIN
Без правильно прописанного DOMAIN не работают push-уведомления и WebAuthn. Полный URL с протоколом, без trailing slash.
Reverse proxy
127.0.0.1:8080 наружу не торчит. Чтобы открыть, нужен reverse proxy с TLS — настройка отдельная, не буду в этом посте, и так длинно. Главное в проксе — пробросить X-Forwarded-Proto и X-Forwarded-For, иначе Vaultwarden будет ругаться на mismatch протоколов.
Бэкап
База — это sqlite-файл data/db.sqlite3 плюс пара папок с аттачами и сендами. Бэкап через systemd-timer, раз в сутки в 04:00:
#!/bin/bash
set -euo pipefail
DATE=$(date +%F)
cd /opt/services/vaultwarden
sqlite3 data/db.sqlite3 ".backup data/db.sqlite3.bak"
tar czf /var/backups/vaultwarden-$DATE.tar.gz \
data/db.sqlite3.bak data/attachments data/sends
rm data/db.sqlite3.bak
.backup через sqlite3 безопаснее cp на живой базе — гарантирует консистентность даже если в этот момент идёт запись.
Старые бэкапы чищу через find -mtime в отдельном скрипте раз в неделю.
Миграция из Bitwarden Cloud
Делается из веба. Settings → Tools → Export vault → JSON (encrypted), скачивается файл. Потом в Vaultwarden: Tools → Import data → Bitwarden (json) → выбрать файл.
Vault'ы переезжают как есть, включая folders. Аттачи приходится переименовать руками — Bitwarden Cloud экспортит их с генерёнными именами, после импорта они называются как угодно. У меня их было пять штук, перенёс руками.
После миграции — выходишь из Bitwarden Cloud со всех устройств, ставишь свой сервер в клиентах, входишь заново. Браузерные расширения и мобильное приложение поддерживают custom server URL — настройка на странице логина, до ввода email.
Что в итоге
Поставил позавчера, базу залил из Bitwarden Cloud, клиенты подружились. Пока работает. Память — 80 MB, диск вместе с парой десятков паролей и пятью аттачами — 12 MB. По сравнению с облачной нет push-уведомлений на новые входы (нужен отдельный Bitwarden Push Server, я его не ставил).
Дальше думаю про Memos — короткие заметки, типа Twitter для самого себя.