Безопасность · :8080

Развертывание Vaultwarden в Docker на Synology

Полное практическое руководство: тома, docker-compose, обязательный HTTPS, админ-панель, почта, бэкапы и харденинг — всё, через что я сам проходил, поднимая приватный Bitwarden на своём NAS.

Зачем вообще хостить пароли самому

Когда я в очередной раз увидел новость об утечке из очередного облачного сервиса, стало окончательно понятно: хранить связку из полутора сотен паролей у стороннего провайдера — это удобно, но требует слепого доверия к чужой инфраструктуре, которую ты не контролируешь и не видишь. Vaultwarden решает именно эту проблему: та же экосистема клиентов Bitwarden (расширения для браузера, мобильные приложения, десктоп), но база данных физически лежит на моём NAS, а не где-то в дата-центре третьей компании.

Это не значит, что self-hosting снимает ответственность за безопасность — наоборот, теперь она полностью на вас. Зато пропадает риск массовой утечки «чужих» паролей вместе с миллионами других учётных записей, и вы точно знаете, кто и когда имел доступ к серверу.

◆ примечание
Эта статья — не «сделайте вот так и всё заработает за пять минут». Vaultwarden — это часть вашей инфраструктуры аутентификации, поэтому я разбираю не только команду запуска, но и то, что вокруг неё: сеть, сертификаты, бэкапы и восстановление после сбоя.

Vaultwarden против официального Bitwarden

Vaultwarden — это независимая реализация серверной части протокола Bitwarden на Rust (изначально проект назывался bitwarden_rs). Он совместим с официальными клиентами, но не является продуктом компании Bitwarden Inc., поэтому не получает патчи безопасности напрямую от них — обновления делает community, и делает их довольно оперативно.

ПараметрVaultwardenBitwarden (официальный self-host)
Потребление RAM≈ 25–60 МБот 2–4 ГБ (набор микросервисов)
Организации и 2FAвключены бесплатночасть в платной подписке
Официальная поддержканет, communityда
Подходит дляhomelab, семья, небольшая командапредприятия с требованиями к SLA

Для одного NAS, семьи из нескольких человек и пары десятков расширенных фич вроде совместных сейфов и отчётов о слабых паролях Vaultwarden закрывает вопрос полностью, при этом почти не потребляя ресурсы, которые на том же хосте нужны для Nextcloud, Home Assistant и прочего.

Что понадобится перед стартом

Шаг 1 — каталоги и права доступа

01Создаём структуру томов

Прежде чем писать compose-файл, разведите данные и конфигурацию по отдельным подпапкам — это сильно упростит бэкапы и перенос на другой NAS в будущем. Через File Station или по SSH создайте:

ssh · admin@nas
mkdir -p /volume1/docker/vaultwarden/data
mkdir -p /volume1/docker/vaultwarden/backups
chown -R 1000:1000 /volume1/docker/vaultwarden

Папка data будет содержать зашифрованную SQLite-базу, вложения и ключи для 2FA — по сути, это единственное, что нужно бэкапить, чтобы полностью восстановить сервис. Отдельная папка backups пригодится в шаге 7.

⚠ важно
Не размещайте data внутри общей папки, синхронизируемой Cloud Sync или похожими инструментами «на лету» — блокировки файла SQLite во время записи иногда конфликтуют с фоновой синхронизацией и приводят к повреждению базы.

Шаг 2 — docker-compose.yml построчно

02Собираем конфигурацию

Вынесем секреты в отдельный .env, а не будем хардкодить их прямо в compose-файле — так его можно спокойно держать в приватном git-репозитории:

.env
DOMAIN=https://vault.мойдомен.ру
ADMIN_TOKEN_HASH=$argon2id$v=19$m=65540,t=3,p=4$...
TZ=Europe/Moscow

Значение ADMIN_TOKEN_HASH мы сгенерируем в шаге 5 — пока просто оставьте место под переменную. Сам compose-файл выглядит так:

docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:1.32.7
    container_name: vaultwarden
    restart: unless-stopped
    env_file: .env
    environment:
      SIGNUPS_ALLOWED: "false"
      INVITATIONS_ALLOWED: "true"
      WEBSOCKET_ENABLED: "true"
      LOG_LEVEL: "warn"
      ROCKET_PORT: "80"
      DOMAIN: "${DOMAIN}"
      ADMIN_TOKEN: "${ADMIN_TOKEN_HASH}"
    volumes:
      - /volume1/docker/vaultwarden/data:/data
    ports:
      - "127.0.0.1:8080:80"
      - "127.0.0.1:3012:3012"
    networks:
      - vaultwarden-net

networks:
  vaultwarden-net:
    driver: bridge

Несколько решений здесь неочевидны и стоят пояснения:

Шаг 3 — первый запуск и проверка

03Поднимаем стек

ssh · admin@nas
cd /volume1/docker/vaultwarden
docker compose up -d
docker compose logs -f vaultwarden

В логах должна появиться строка о старте Rocket на порту 80 без ошибок подключения к базе. На этом этапе сервис уже доступен локально по адресу http://ip-нас:8080 — но заходить и создавать аккаунт стоит только после того, как поднят HTTPS: клиенты Bitwarden (и веб-расширение) требовательны к защищённому соединению и часть функций без него просто не активируется.

Шаг 4 — HTTPS через Nginx Proxy Manager

04Настраиваем проксирование

В Nginx Proxy Manager создайте новый Proxy Host с доменом vault.мойдомен.ру, указывающим на IP NAS и порт 8080. Отдельное внимание — вкладке WebSockets, без которой синхронизация в реальном времени работать не будет:

клиент nginx proxy manager :443 · tls · websocket vaultwarden :8080 / :3012

Обязательно добавьте два кастомных заголовка в конфигурацию хоста — Vaultwarden не работает корректно без прямой передачи реального IP и протокола:

nginx · custom locations
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

Сертификат Let's Encrypt выпускается прямо из интерфейса NPM — включите форс-редирект на HTTPS и HSTS во вкладке SSL, это закроет обычную ошибку «клиент не может подключиться» на мобильных устройствах, которые не принимают самоподписанные сертификаты.

Шаг 5 — админ-панель и ADMIN_TOKEN

05Защищаем панель администратора

Панель /admin даёт полный контроль над пользователями сервера, поэтому токен для неё должен храниться в виде хэша, а не открытым текстом — с версии 1.30 Vaultwarden поддерживает именно такой формат. Сгенерировать его можно прямо через контейнер:

ssh · admin@nas
docker exec -it vaultwarden ./vaultwarden hash

Команда попросит ввести пароль дважды и выведет строку вида $argon2id$v=19$m=65540,t=3,p=4$... — именно её вставьте в ADMIN_TOKEN_HASH в файле .env и перезапустите стек командой docker compose up -d.

Открытый текстовый ADMIN_TOKEN в переменных окружения — практически то же самое, что пароль root в комментарии к коду: рано или поздно он попадёт в бэкап, лог или чужие руки.

Шаг 6 — почта для приглашений и восстановления

06Подключаем SMTP

Без настроенной почты приглашения в организацию и сброс пароля превращаются в ручную возню со ссылками из логов контейнера. Для личного использования достаточно приложения-пароля от Gmail или Яндекс.Почты:

.env · добавить
SMTP_HOST=smtp.yandex.ru
SMTP_FROM=vault-noreply@мойдомен.ру
SMTP_PORT=465
SMTP_SECURITY=force_tls
SMTP_USERNAME=vault-noreply@мойдомен.ру
SMTP_PASSWORD=пароль-приложения

После перезапуска проверьте отправку через саму админ-панель — там есть отдельная кнопка тестового письма, которая избавляет от необходимости регистрировать тестовый аккаунт вслепую.

Шаг 7 — бэкапы, которые реально спасают

07Автоматизируем резервное копирование

SQLite не любит копирование «на горячую» через обычный cp — файл может оказаться в промежуточном состоянии записи. Правильный способ — встроенная команда бэкапа самой базы, которая гарантирует консистентный снимок:

backup.sh
#!/bin/bash
STAMP=$(date +%Y%m%d-%H%M)
DEST=/volume1/docker/vaultwarden/backups
docker exec vaultwarden sqlite3 /data/db.sqlite3 ".backup '/data/backup-tmp.sqlite3'"
docker exec vaultwarden mv /data/backup-tmp.sqlite3 /data/backup-tmp.sqlite3.done
docker cp vaultwarden:/data/backup-tmp.sqlite3.done "$DEST/db-$STAMP.sqlite3"
docker exec vaultwarden rm /data/backup-tmp.sqlite3.done
find "$DEST" -name "db-*.sqlite3" -mtime +14 -delete

Повесьте скрипт на планировщик задач Synology (Task Scheduler → «Запланированная задача» → «Пользовательский скрипт») на ежедневный запуск ночью. Отдельно скопируйте и папку attachments внутри data, если в сейфах есть вложенные файлы — сам скрипт бэкапит только базу данных.

✓ совет
Раз в квартал восстанавливайте бэкап на тестовом контейнере и реально логиньтесь в него. Бэкап, который никогда не проверяли на восстановление, статистически равносилен его отсутствию.

Харденинг: что подкрутить сверх дефолта

Обновления и обслуживание

Проверяйте changelog на странице релизов Vaultwarden перед каждым обновлением — иногда меняется формат переменных окружения. Сам процесс простой:

ssh · admin@nas
./backup.sh
docker compose pull vaultwarden
docker compose up -d
docker compose logs -f vaultwarden

Запуск бэкапа перед обновлением — не паранойя, а привычка, которая один раз действительно спасёт вечер.

Частые проблемы и их причины

СимптомВероятная причина
синхронизация с задержкойне проброшен или не проксирован порт 3012 (websocket)
мобильное приложение не подключаетсясертификат не покрывает поддомен, либо не включён форс-HTTPS
«invalid admin token»в .env остался старый нехэшированный токен после обновления образа
письма не приходятSMTP_SECURITY не соответствует порту (465 требует force_tls, 587 — starttls)
база «database is locked»синхронизация тома облачным клиентом поверх папки data

Если после всех шагов сервис поднялся, сертификат зелёный, а 2FA включена — на этом Vaultwarden можно спокойно доверить пароли от всей остальной инфраструктуры, которую вы разворачиваете на этом же NAS.