MAATRIX / Блог / Как установить и настроить Vaultwarden на VPS

Как установить и настроить Vaultwarden на VPS

Как установить и настроить Vaultwarden на VPS

MAATRIX

Официальный self-hosted Bitwarden — это одиннадцать контейнеров, MSSQL и рекомендованные 4 ГБ памяти под хранилище паролей на десять человек. Vaultwarden делает то же самое одним процессом на Rust и занимает около 50 МБ. Ниже — установка на чистый VPS по шагам, с командой проверки после каждого этапа.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что вы получаете вместо официального Bitwarden

Vaultwarden — независимая реализация серверного API Bitwarden на Rust. Клиенты остаются родные: браузерное расширение, десктоп, приложения для iOS и Android, CLI. В настройках клиента вы указываете свой адрес вместо vault.bitwarden.com — больше ничего не меняется.

Разница в аппетитах видна сразу. Официальная сборка поднимает десяток сервисных контейнеров плюс MSSQL, её требования — 2 ядра, от 2 ГБ памяти и 12 ГБ диска. Vaultwarden — один контейнер и файл SQLite: docker stats через сутки работы с семью активными пользователями показывает 48.7MiB / 1.918GiB и 0,03 % CPU. Бесплатно открыты организации и коллекции, TOTP внутри записей, вложения, экстренный доступ, ключи WebAuthn.

Минусы честные. Проект неофициальный, компания Bitwarden его не поддерживает, аудитов уровня облака у него нет. Поддержка OIDC/SSO появилась в ветке 1.34 со статусом экспериментальной — опираться на неё в корпоративном контуре рано. И вместе с сервером вы забираете ответственность за бэкапы и доступность. Разбор «кому что выгоднее» — в материале Vaultwarden против Bitwarden.

Подготовка: домен, DNS, фаервол и часы

Домен обязателен, HTTPS обязателен. Веб-хранилище шифрует всё в браузере через WebCrypto, а crypto.subtle доступен только в защищённом контексте: по http:// страница входа откроется, но при вводе пароля повиснет с TypeError: Cannot read properties of undefined (reading 'subtle') в консоли. Самоподписанный сертификат тоже не выход — расширение отвечает Failed to fetch, мобильное приложение Trust anchor for certification path not found.

Заведите A-запись и проверьте: dig +short vault.example.com должен вернуть IP сервера. Наружу открываем только SSH и веб — ufw allow 22/tcp && ufw allow 80,443/tcp && ufw enable; порт контейнера в мир не публикуем вообще.

Отдельно про часы. Vaultwarden сверяет коды двухфакторки на своей стороне, окно допуска — плюс-минус один шаг по 30 секунд, и сервер, уехавший на минуту, встретит вас Invalid TOTP code! при правильном коде из телефона. timedatectl должен показывать System clock synchronized: yes.

Docker ставьте из репозитория вендора — curl -fsSL https://get.docker.com | sh, в дистрибутивных пакетах версия старше примерно на год. Система — Ubuntu 24.04 LTS или Debian 13, различий для Vaultwarden нет.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть Vaultwarden

Установка: Docker Compose и первый запуск

Раскладываем всё в /opt/vaultwarden. Ключевое решение — публикация порта только на петлю 127.0.0.1:8080: контейнер физически недоступен снаружи мимо реверс-прокси, даже если вы ошибётесь в правилах ufw.

# /opt/vaultwarden/compose.yaml
services:
  vaultwarden:
    image: vaultwarden/server:1.34.3
    container_name: vaultwarden
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - ./vw-data:/data
    env_file: vaultwarden.env

Тег версии закрепляем осознанно: latest удобен, пока не приезжает изменение, ломающее конфиг посреди рабочего дня. Текущую версию покажет docker exec vaultwarden /vaultwarden --version.

Переменные — в отдельном файле. Не называйте его .env: этот файл Compose дополнительно читает для подстановки переменных в сам compose-файл, и символ $ в значениях начинает жить своей жизнью. Имя vaultwarden.env снимает вопрос.

DOMAIN=https://vault.example.com
SIGNUPS_ALLOWED=true
INVITATIONS_ALLOWED=true
LOG_FILE=/data/vaultwarden.log
LOG_LEVEL=warn
EXTENDED_LOGGING=true

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

Запуск — docker compose up -d, проверка — curl -s http://127.0.0.1:8080/alive. В логе docker compose logs vaultwarden ищите строку [INFO] Rocket has launched from http://0.0.0.0:80, а /alive вернёт время сервера вида "2026-08-28T09:41:22.518293151Z". Ответ пришёл — приложение живо, дальше воюем только с прокси.

В vw-data/ появятся db.sqlite3 (всё хранилище), attachments/, sends/, icon_cache/ и rsa_key.pem. Незаменимы первые два. Потеря rsa_key.pem данные не уничтожает — она разлогинивает всех разом, потому что старые токены перестают проверяться.

Nginx, TLS и вебсокеты: где ломаются старые гайды

Сертификат берём у Let's Encrypt: apt install -y nginx certbot python3-certbot-nginx, затем certbot --nginx -d vault.example.com — пути к сертификату он впишет сам. Руками добавляем два места: client_max_body_size (по умолчанию Nginx режет тело на 1 МБ, и вложение крупнее падает с 413 Request Entity Too Large) и апгрейд соединения на /notifications/hub.

server {
    listen 443 ssl;
    server_name vault.example.com;
    client_max_body_size 128M;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host            $host;
        proxy_set_header X-Real-IP       $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /notifications/hub {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host       $host;
        proxy_read_timeout 3600s;
    }
}

Главная грабля 2026 года — копирование гайдов трёхлетней давности. До версии 1.32.0 вебсокеты жили на отдельном порту 3012 и включались переменной WEBSOCKET_ENABLED=true. С 1.32.0 их обслуживает основной порт, WEBSOCKET_ENABLED игнорируется, а 3012 не слушает никто. Старый конфиг с proxy_pass http://127.0.0.1:3012; даёт 502 Bad Gateway на /notifications/hub при полностью рабочем входе — внешне это выглядит как «изменения не долетают между устройствами».

Второй нюанс — адрес клиента. Vaultwarden читает заголовок X-Real-IP (переменная IP_HEADER); если прокси его не ставит, в лог по каждой неудачной попытке входа поедет IP: 127.0.0.1, и fail2ban из следующего раздела будет героически банить локалхост. За Cloudflare ставьте IP_HEADER=X-Forwarded-For.

Не хотите возиться с Nginx — Caddy закрывает вопрос тремя строками, сам выпускает сертификат и корректно апгрейдит вебсокеты (Caddy с авто-SSL на VPS):

vault.example.com {
    reverse_proxy 127.0.0.1:8080
}

Первый пользователь, ADMIN_TOKEN и закрытие регистрации

Откройте https://vault.example.com, зарегистрируйте свою учётку — и сразу закройте вход посторонним. Открытая регистрация на публичном адресе за неделю набирает десятки чужих аккаунтов, найденных сканерами.

SIGNUPS_ALLOWED=false
INVITATIONS_ALLOWED=true
SIGNUPS_DOMAINS_WHITELIST=example.com
ORG_CREATION_USERS=admin@example.com

Теперь панель /admin. Открытым текстом токен писать не нужно — Vaultwarden принимает Argon2 PHC-строку и генерирует её сам: docker exec -it vaultwarden /vaultwarden hash --preset owasp. Команда дважды спросит пароль и выдаст строку вида $argon2id$v=19$m=19456,t=2,p=1$c29tZXNhbHQ$.... Пресет owasp просит 19 МБ памяти на проверку, пресет по умолчанию bitwarden — 64 МБ; на маленьком сервере разница ощутима. Оставите обычную строку — при каждом старте в лог пойдёт предупреждение You are using a plain text ADMIN_TOKEN which is insecure.

Про доллары в хеше — отдельно, потому что на этом спотыкаются все. Готовую строку кладите в vaultwarden.env как есть, без кавычек: значения из env_file передаются в контейнер дословно. А если вписать её прямо в environment: внутри compose-файла, Compose попытается подставить переменные, напишет WARN[0000] The "argon2id" variable is not set. Defaulting to a blank string. и отдаст контейнеру огрызок — там каждый $ надо удвоить до $. Проверка в обоих случаях одна: docker exec vaultwarden printenv ADMIN_TOKEN, строка должна быть целой и начинаться с $argon2id$.

Панель /admin — самая лакомая точка на сервере. Притормозите перебор через ADMIN_RATELIMIT_SECONDS=300 и ADMIN_RATELIMIT_MAX_BURST=3, а если снаружи она не нужна — выключите совсем через DISABLE_ADMIN_TOKEN=true либо пустите только со своего адреса блоком location /admin { allow 203.0.113.10; deny all; proxy_pass http://127.0.0.1:8080; }.

И ловушка, стоящая часа отладки: настройки, сохранённые кнопкой в веб-панели, ложатся в /data/config.json и перекрывают переменные окружения. После этого правки в vaultwarden.env ни на что не влияют, хотя перезапуск проходит без ошибок. Решайте один раз: либо всё через файл окружения (тогда cat vw-data/config.json показывает пустой {}), либо всё через панель.

Почта, push на телефоны и защита от перебора

Без SMTP не работают приглашения, письма верификации и уведомления о входе с нового устройства. Заполняете SMTP_HOST, SMTP_FROM, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD и SMTP_SECURITY. Последняя принимает три значения: starttls для порта 587, force_tls для 465 и off для 25. Перепутанная пара «порт плюс режим» — самая частая причина, по которой тестовое письмо из /admin заканчивается таймаутом; ошибка аутентификации выглядит понятнее: SMTP 5xx error: permanent error (535): 5.7.8 Error: authentication failed. Отправлять с 25-го порта напрямую не пытайтесь, почти все провайдеры его блокируют.

Мобильные приложения синхронизируются не по вебсокетам, а через push. Своего сервиса у Vaultwarden нет, он использует официальный ретранслятор Bitwarden: зарегистрируйте бесплатный идентификатор установки на bitwarden.com/host и добавьте PUSH_ENABLED=true, PUSH_INSTALLATION_ID, PUSH_INSTALLATION_KEY, PUSH_RELAY_URI=https://push.bitwarden.eu и PUSH_IDENTITY_URI=https://identity.bitwarden.eu. Регион важен: европейский идентификатор работает только с адресами bitwarden.eu, американский — только с bitwarden.com. Перепутали — в логе ошибка авторизации push, а телефон подтягивает изменения только вручную (Vaultwarden не синхронизируется).

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

[2026-08-28 09:52:14.031][vaultwarden::api::identity][ERROR] Username or password is
incorrect. Try again. IP: 203.0.113.45. Username: user@example.com.

Отсюда фильтр /etc/fail2ban/filter.d/vaultwarden.conf и джейл /etc/fail2ban/jail.d/vaultwarden.local:

[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$

[vaultwarden]
enabled  = true
port     = 80,443
filter   = vaultwarden
logpath  = /opt/vaultwarden/vw-data/vaultwarden.log
maxretry = 5
findtime = 600
bantime  = 3600

Проверяйте не веру, а вывод fail2ban-client status vaultwarden. Ноль в Total failed при явных попытках в логе означает, что регулярка не совпала: тексты сообщений между ветками менялись, сверьтесь через grep -m1 'incorrect' vw-data/vaultwarden.log. Общая настройка сервиса — в статье Fail2ban на VPS.

Последнее по порядку и первое по важности — бэкап. Копировать db.sqlite3 обычным cp во время работы нельзя: получите файл с оборванной транзакцией, и выяснится это в момент восстановления. Правильно — sqlite3 vw-data/db.sqlite3 ".backup '/root/vw-$(date +%F).sqlite3'", плюс каталог attachments/, плюс выгрузка на другую машину. Схема с шифрованием и проверкой восстановления — в материале Vaultwarden: бэкап и восстановление паролей.

Какой сервер под Vaultwarden брать в MAATRIX

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

Минимум: 1 vCPU, 1 ГБ RAM, 20 ГБ NVMe. Хватает на команду из 10–20 человек с запасом: контейнер держится в районе 50 МБ, ещё 100–150 МБ уходит на демон Docker, Nginx и fail2ban. Ограничение честное — на 1 ГБ не стоит собирать Vaultwarden из исходников: компилятору Rust нужно 2 ГБ и больше, сборка упадёт с signal: 9, SIGKILL: kill от OOM-киллера. Ставьте готовый образ, он весит около 200 МБ.

Комфортный вариант: 2 vCPU, 2–4 ГБ RAM, 40 ГБ NVMe. Разница не в скорости входа, а в том, что рядом помещается остальное: локальные бэкапы за месяц, Postgres вместо SQLite (актуально от полусотни активных пользователей), вложения и снапшоты. Диск съедают именно вложения — ограничьте аппетит через USER_ATTACHMENT_LIMIT=102400, это 100 МБ на пользователя в килобайтах.

Приложения из каталога apps.maatrix.io ставятся на сервер автоматически при заказе: вставлять команды из этой статьи руками не нужно. Автоустановка работает на Ubuntu и Debian, доступы появляются в личном кабинете в разделе «Доступ». Ваша часть после этого — направить A-запись на выданный IP, выпустить сертификат и пройтись по разделам про ADMIN_TOKEN и SMTP.

Локация — Великобритания, Лондон. Аргумент здесь не скорость: хранилище синхронизирует килобайты, лишние 30 мс не заметит никто. Выбор про юрисдикцию и стабильность адреса — европейское правовое поле, соседство с GDPR, чистый IP без репутации предыдущих жильцов и прямой доступ к европейскому push-ретранслятору bitwarden.eu. RTT из Москвы — около 45–55 мс, из Берлина и Амстердама единицы миллисекунд, что удобно распределённой команде. Если в хранилище лежат персональные данные российских сотрудников и вы под 152-ФЗ — берите российскую локацию (где законно держать сервер с персональными данными).

Оплата — картами российских банков, по СБП, криптовалютой или токеном MAAT: иностранная карта не нужна, хотя сервер стоит в Лондоне. И трезвая оговорка: один сервер — одна точка отказа. Свой Vaultwarden дешевле и приватнее облака, но резервные копии на другую машину здесь не «хорошая практика», а условие, при котором вся затея имеет смысл.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть Vaultwarden

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Можно ли обойтись без домена и работать по IP?

Практически нет. Клиенты Bitwarden требуют валидный HTTPS: с самоподписанным сертификатом расширение отвечает Failed to fetch, а мобильное приложение отказывается доверять цепочке. Домен плюс сертификат Let's Encrypt — минимальный рабочий комплект.

Забыл ADMIN_TOKEN, как попасть в /admin?

Восстанавливать нечего — сгенерируйте новый через docker exec -it vaultwarden /vaultwarden hash --preset owasp и замените значение. Если вы сохраняли настройки кнопкой в панели, токен лежит в /data/config.json и перекрывает переменную окружения: правьте там же.

Что произойдёт, если сервер пропадёт?

Уже авторизованные клиенты продолжат открывать хранилище — у них есть локальная зашифрованная копия. Перестанут работать синхронизация и вход на новых устройствах. Восстановление требует db.sqlite3 и каталога attachments/; мастер-пароль по устройству архитектуры не восстанавливается ничем.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.