Vaultwarden — совместимый с клиентами Bitwarden сервер, который развивает независимое open-source сообщество. Это не официальный продукт Bitwarden и не сервис, который можно установить один раз и забыть. При самостоятельном размещении вы отвечаете за обновления, HTTPS, резервные копии и доступность хранилища.
Ниже — небольшой вариант для одного пользователя или семьи: SQLite, Caddy, закрытая после первого входа регистрация и без публичного порта контейнера.
На момент подготовки инструкции актуальный release — 1.36.0. Он содержит исправления безопасности, поэтому старые примеры с многолетними тегами использовать не стоит.
Что потребуется
- Linux-сервер с Docker Engine и Compose plugin;
- отдельный домен, например
vault.example.ru;
- Caddy в общей сети
homelab_proxy;
- внешний канал для резервных копий;
- время на пробное восстановление до переноса реальных паролей.
Web Vault и WebAuthn требуют безопасного контекста. Для доступа не из localhost нужен нормальный HTTPS с доверенным сертификатом. Не публикуйте Vaultwarden по обычному HTTP в локальной сети.
Каталоги
sudo mkdir -p /opt/vaultwarden/data
sudo chown -R "$USER":"$USER" /opt/vaultwarden
cd /opt/vaultwarden
docker network inspect homelab_proxy >/dev/null 2>&1 \
|| docker network create homelab_proxy
compose.yaml
Для самого первого запуска временно оставьте регистрацию включённой:
services:
vaultwarden:
image: vaultwarden/server:1.36.0
restart: unless-stopped
environment:
DOMAIN: "https://vault.example.ru"
SIGNUPS_ALLOWED: "true"
INVITATIONS_ALLOWED: "false"
volumes:
- type: bind
source: ./data
target: /data
networks:
- proxy
networks:
proxy:
external: true
name: homelab_proxy
Замените домен своим. Порта 80:80 нет: к контейнеру обращается только Caddy внутри общей сети.
SQLite подходит для небольшой установки и является стандартным простым вариантом Vaultwarden. Каталог /data содержит не только базу, но и вложения, ключи подписи токенов, настройки и другие файлы. Сохранение одного db.sqlite3 не является полной копией сервиса.
Caddyfile
Добавьте в /opt/caddy/conf/Caddyfile:
vault.example.ru {
encode zstd gzip
reverse_proxy vaultwarden:80
}
Проверьте и примените:
cd /opt/caddy
docker compose exec caddy \
caddy validate --config /etc/caddy/Caddyfile
docker compose exec caddy \
caddy reload --config /etc/caddy/Caddyfile
Caddy проксирует WebSocket автоматически. Старые инструкции Vaultwarden часто содержат отдельный маршрут /notifications/hub; для современного Caddy в одной Docker-сети достаточно обычного reverse_proxy всего сервиса.
Первый запуск и закрытие регистрации
cd /opt/vaultwarden
docker compose config
docker compose up -d
docker compose ps
docker compose logs -f --tail=100 vaultwarden
Откройте https://vault.example.ru, создайте единственную нужную учётную запись и убедитесь, что можете войти повторно.
Сразу после этого измените:
SIGNUPS_ALLOWED: "false"
И пересоздайте контейнер:
docker compose up -d
docker compose logs --since=5m vaultwarden
Откройте страницу регистрации в приватном окне и проверьте, что создать нового пользователя нельзя. Не полагайтесь только на значение в YAML: настройки, сохранённые через /admin, попадают в data/config.json и имеют приоритет над соответствующими environment-переменными.
Для семейной установки лучше временно разрешать приглашения на конкретные адреса через контролируемый процесс, а не оставлять свободную регистрацию навсегда.
Нужна ли страница /admin
Без ADMIN_TOKEN административная страница отключена. Для простой установки это нормальный и наиболее спокойный вариант: основные действия с контейнером выполняются через Compose, а пользователи управляют своими vault через обычный интерфейс.
Если /admin действительно нужен, не задавайте обычный пароль открытым текстом. Сгенерируйте Argon2id PHC встроенной командой:
docker run --rm -it vaultwarden/server:1.36.0 \
/vaultwarden hash
Команда попросит пароль дважды и выведет строку, начинающуюся с $argon2id$. Сохраните её в /opt/vaultwarden/.env:
VAULTWARDEN_ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$ЗАМЕНИТЕ$РЕАЛЬНЫМ_ХЕШЕМ'
Ограничьте права:
chmod 600 /opt/vaultwarden/.env
Добавьте в environment сервиса:
ADMIN_TOKEN: ${VAULTWARDEN_ADMIN_TOKEN}
В .env одинарные кавычки сохраняют символы $ без подстановки Compose. Если вставлять PHC прямо в compose.yaml, каждый $ придётся удваивать как $$. Не копируйте примерный хеш из инструкции: сгенерируйте свой.
Даже с хешем /admin остаётся высокопривилегированной панелью. Ограничьте её через VPN или отдельную политику reverse proxy и не увеличивайте время административной сессии без причины.
Настройка клиентов
В официальном клиенте Bitwarden выберите self-hosted server и укажите:
https://vault.example.ru
Сначала проверьте вход в браузере, затем в мобильном и настольном клиентах. После успешной синхронизации:
- включите TOTP или аппаратный второй фактор;
- сохраните recovery code отдельно от Vaultwarden;
- проверьте блокировку клиента по таймауту;
- сделайте тестовую запись и дождитесь её появления на втором устройстве;
- не переносите все пароли до первой проверенной резервной копии.
Self-hosted сервер не отменяет шифрование клиента, но его компрометация всё равно опасна: злоумышленник может красть зашифрованные данные, подменять веб-интерфейс и ждать ввода master password. Поэтому защита сервера и своевременные обновления обязательны.
Почта
SMTP нужен для приглашений и части уведомлений. Не записывайте реальный пароль прямо в Compose, который отправляется в Git. Храните параметры в .env с правами 600 или используйте поддерживаемый механизм секретов.
Типовой набор переменных:
SMTP_HOST='smtp.example.ru'
SMTP_FROM='vault@example.ru'
SMTP_FROM_NAME='Vaultwarden'
SMTP_SECURITY='starttls'
SMTP_PORT='587'
SMTP_USERNAME='vault@example.ru'
SMTP_PASSWORD='ЗАМЕНИТЕ_РЕАЛЬНЫМ_ПАРОЛЕМ'
А в Compose передайте только ссылки на них:
environment:
SMTP_HOST: ${SMTP_HOST}
SMTP_FROM: ${SMTP_FROM}
SMTP_FROM_NAME: ${SMTP_FROM_NAME}
SMTP_SECURITY: ${SMTP_SECURITY}
SMTP_PORT: ${SMTP_PORT}
SMTP_USERNAME: ${SMTP_USERNAME}
SMTP_PASSWORD: ${SMTP_PASSWORD}
После настройки отправьте тестовое письмо через admin-панель, если она включена. Не считайте SMTP рабочим только потому, что контейнер запустился.
Резервная копия
В Vaultwarden есть встроенная команда для согласованной копии SQLite:
cd /opt/vaultwarden
docker compose exec -T vaultwarden /vaultwarden backup
Она создаёт отдельный файл базы в /data. Но вложения, Sends, RSA-ключи и config.json находятся рядом, поэтому сохраните весь каталог после короткой остановки:
backup_dir="$HOME/backups/vaultwarden-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$backup_dir"
docker compose stop vaultwarden
sudo tar -C /opt/vaultwarden -czf \
"$backup_dir/vaultwarden-data.tar.gz" \
data compose.yaml .env
docker compose start vaultwarden
sha256sum "$backup_dir/vaultwarden-data.tar.gz" \
> "$backup_dir/SHA256SUMS"
Если .env не используется, удалите его из команды tar. Если остановка или архивирование завершились ошибкой, сначала верните сервис через docker compose start vaultwarden.
Копия содержит токены, SMTP-пароль, метаданные и ключи сервера. Даже если сами vault-записи зашифрованы, архив нужно дополнительно шифровать и хранить вне исходного сервера.
Для восстановления SQLite из встроенного backup остановите Vaultwarden и не оставляйте рядом старый несовместимый db.sqlite3-wal. Официальная документация предупреждает: stale WAL от другой копии базы может привести к повреждению данных.
Проверку восстановления проводите на отдельном хосте или в изолированном Compose-проекте с другим доменом, отключённым SMTP и без доступа к рабочему reverse proxy. Успешный вход и чтение одной записи недостаточны — проверьте вложение, синхронизацию второго клиента и создание новой тестовой записи.
Обновление
Vaultwarden хранит самые ценные данные homelab, поэтому автоматическое ночное обновление без release notes — плохая идея.
Порядок:
- прочитайте заметки нового release и security advisories;
- выполните встроенный backup и архив
/data;
- замените tag образа в
compose.yaml на проверенную версию;
- загрузите образ и пересоздайте контейнер;
- проверьте браузерный и мобильный клиент.
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --since=10m vaultwarden
Не откатывайте только image после миграции данных, не проверив совместимость старой версии с новой базой. Для возврата используйте комплект образа и данных, созданный до обновления.
Типовые проблемы
В браузере работает, а мобильный клиент не подключается
Проверьте полный server URL, цепочку сертификата и доступ с мобильного интернета. Самоподписанный сертификат без установленного доверенного CA клиенты отвергнут.
curl -fsS https://vault.example.ru/alive
Не загружаются вложения
Убедитесь, что DOMAIN точно совпадает с внешним HTTPS-адресом, а Caddy передаёт запрос всему сервису. Не указывайте внутреннее имя контейнера в DOMAIN.
Регистрация осталась открытой после SIGNUPS_ALLOWED=false
Проверьте data/config.json. Если настройки когда-то сохранялись через /admin, они могут перекрывать environment. Меняйте конфигурацию в одном понятном месте и после изменения пересоздавайте контейнер.
ADMIN_TOKEN не принимается
Чаще всего Compose попытался интерпретировать части $argon2id$... как переменные или в значение попали лишние кавычки. Проверьте итоговую конфигурацию локально, но не публикуйте её вывод: он содержит секреты.
После восстановления база повреждена
Не смешивайте db.sqlite3 из одного момента и db.sqlite3-wal из другого. Используйте встроенный /vaultwarden backup или SQLite Online Backup API, а восстановление проводите на остановленном сервисе по официальной инструкции.
Официальные источники