SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor

Установка Vaultwarden на VPS через Docker

Разверните менеджер паролей Vaultwarden на собственном VPS. В статье описана настройка TLS, использование admin token, защита Fail2ban и надежная схема резервного копирования.

Что вы создаете

Менеджер паролей, который полностью принадлежит вам: Vaultwarden, работающий в одном небольшом контейнере за reverse proxy, который выполняет TLS termination, с официальными приложениями Bitwarden на вашем телефоне, ноутбуке и в браузере, настроенными на работу с ним. Vaultwarden перереализует API сервера Bitwarden на языке Rust и использует тот же протокол, что и bitwarden.com, поэтому официальные клиенты работают с ним без изменений, пока вы поддерживаете сервер в актуальном состоянии (новые версии клиентов иногда требуют соответствующего релиза Vaultwarden: версия 1.37.2 необходима для клиентов 2026.8.0 и новее), но при этом он потребляет около 100 MB оперативной памяти вместо многоконтейнерного официального стека.

Сама установка занимает около 12 строк в Compose. Три вещи, которые действительно важны и которые могут привести к сбоям: TLS должен быть настроен до того, как вы впервые загрузите веб-интерфейс хранилища, публичную регистрацию необходимо закрыть сразу после создания вашей собственной учетной записи, а резервную копию тома с данными нужно создавать и проверять путем тестового восстановления, так как в этой директории хранятся все ваши пароли.

Предварительные требования и важные нюансы

  • VPS с установленным Docker Engine и плагином Compose на чистой системе Ubuntu 24.04 KVM с доступом root или sudo. 512 МБ оперативной памяти вполне достаточно; 1 ГБ обеспечит комфортную работу. Это одно из самых легковесных решений, которое входит в краткий список сервисов, пригодных для self-hosting. Однако выбирайте размер сервера с учетом других задач: размещение self-hosted фотогалереи, такой как PhotoPrism или Immich, на том же VPS потребует уже нескольких гигабайт оперативной памяти, в то время как Vaultwarden потребляет минимум ресурсов. Тот же расчет применим к медиа-серверам, которые вы добавите позже, так как превращение медиатеки Jellyfin в виртуальный видеопрокат 90-х означает запуск еще одного постоянно работающего контейнера и необходимость запаса ресурсов для транскодирования.
  • Домен с A-записью (и AAAA, если у вас есть IPv6), указывающей vault.example.com на ваш VPS. TLS-сертификат выдается строго на это имя, поэтому DNS должен разрешаться до начала настройки.
  • Порты 80 и 443 должны быть открыты для доступа из Интернета и терминироваться вашим reverse proxy, но никогда не напрямую через Vaultwarden. Порт 80 используется только для прохождения ACME-проверки при выдаче сертификата и для редиректа с HTTP на HTTPS.
  • Главный нюанс: клиенты Bitwarden отказываются работать с сервером, если не используется HTTPS. Варианта «сначала протестировать по HTTP» не существует, этот путь не работает по веской причине, которая описана далее.

Почему Vaultwarden, а не официальный стек Bitwarden

Те же клиенты, но значительно меньшее потребление ресурсов. Стандартный официальный self-hosted стек Bitwarden поставляется как набор контейнеров (MSSQL Express, Identity, Api, Admin и другие) и требует минимум 2 ГБ оперативной памяти. Bitwarden также предлагает Bitwarden lite — один Docker-образ, которому нужно от 200 МБ ОЗУ, но он предназначен для личного использования и домашних лабораторий, а не для бизнеса, при этом управление базой данных и её резервным копированием полностью ложится на вас. Vaultwarden — это один бинарный файл, который по умолчанию хранит всё в базе данных SQLite и в режиме ожидания потребляет всего несколько десятков мегабайт. Для одного пользователя, семьи или небольшой команды это очевидный выбор, а поскольку он точно реализует API Bitwarden, ваши данные остаются переносимыми между ним и bitwarden.com.

Вы отказываетесь от большинства корпоративных функций: нет поддержки SCIM-провижининга (хотя поддержка OpenID Connect SSO появилась в версии 1.35.0), и вы являетесь оператором, поэтому установка обновлений, настройка HTTPS и резервное копирование — ваша задача. Это руководство посвящено именно этим трём задачам.

Почему HTTPS не является опциональным

Веб-хранилище Bitwarden и расширения для браузеров вычисляют ваши ключи шифрования в браузере с помощью Web Crypto API (window.crypto.subtle). Браузеры предоставляют доступ к crypto.subtle только в безопасном контексте (HTTPS) или в особых случаях при использовании адресов обратной петли, таких как http://localhost и http://127.0.0.1. При использовании обычного http://vault.example.com доступ к API undefined, поэтому в момент попытки вычисления ключа приложение выдает ошибку, а в консоли отображается:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'importKey')

Страница зависает или выводит общую ошибку криптографии, и вход в систему не выполняется. Десктопные, мобильные и браузерные клиенты выполняют собственную проверку URL при самостоятельном хостинге, и при обращении к http (или недоступной) конечной точке они выдают отказ:

This is not a recognized Bitwarden server. You may need to check with your provider or update your server.

У обеих проблем одна причина: отсутствие корректного HTTPS. Поэтому мы сначала настраиваем TLS и никогда не открываем хранилище по http, даже для быстрой проверки.

Шаг 1, DNS и обратный прокси (сначала TLS)

Укажите запись для вашего VPS и убедитесь, что она разрешается в правильный адрес:

dig +short vault.example.com

В строке вывода должен быть IP-адрес вашего VPS. Если вывод пуст или адрес неверный, исправьте настройки DNS и дождитесь истечения TTL; выпуск сертификата невозможен, если имя не разрешается.

Для HTTPS-фронтенда в этом руководстве используется Traefik, который автоматически выпускает и обновляет сертификаты Let's Encrypt и легко интегрируется в Compose. Если вы его еще не используете, сначала выполните настройку обратного прокси Traefik и автоматического TLS; это создаст внешнюю сеть Docker (proxy ниже) и ACME-резолвер (letsencrypt), к которым подключится сервис Vaultwarden. Обычный nginx с сертификатом, выпущенным вручную, со стороны Vaultwarden работает точно так же.

Предпочитаете nginx и Certbot вместо Traefik? Разместите Vaultwarden на 127.0.0.1:8080 (добавьте ports: ["127.0.0.1:8080:80"] в сервис и удалите метки Traefik), затем выпустите сертификат и настройте проксирование. Часть с сертификатами описана в выпуске сертификатов Let's Encrypt с помощью Certbot и nginx. Важное дополнение — обновление WebSocket для пути уведомлений:

server {
    listen 443 ssl;
    server_name vault.example.com;

    client_max_body_size 525M;

    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;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Обратите внимание на строку X-Real-IP: именно она позволяет Fail2ban в дальнейшем видеть реального атакующего, а не 127.0.0.1. Все остальные действия в этом руководстве идентичны независимо от того, используется ли перед сервисом Traefik или nginx.

Шаг 2: файл Compose

Сначала создайте каталог проекта. В этом руководстве используется /opt/vaultwarden, что делает имя проекта Compose, а следовательно, и имя тома данных vaultwarden_vw-data, предсказуемыми; шаги по настройке Fail2ban и резервному копированию, описанные ниже, зависят от этого конкретного имени.

sudo mkdir -p /opt/vaultwarden
cd /opt/vaultwarden

Создайте .env для секрета администратора и файла Compose в этом каталоге.

# .env
ADMIN_TOKEN=paste-a-strong-token-here

Сгенерируйте этот токен с помощью openssl rand -base64 48 и вставьте его. (Более надежная хешированная форма будет рассмотрена далее; для начала подойдет длинная случайная строка.)

# docker-compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      DOMAIN: "https://vault.example.com"
      SIGNUPS_ALLOWED: "true"          # closed in Step 4, keep true just to register
      ADMIN_TOKEN: "${ADMIN_TOKEN}"
      IP_HEADER: "X-Forwarded-For"     # X-Real-IP if your proxy sends that instead
      LOG_FILE: "/data/vaultwarden.log"
      LOG_LEVEL: "warn"
    volumes:
      - vw-data:/data
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.vw.rule=Host(`vault.example.com`)"
      - "traefik.http.routers.vw.entrypoints=websecure"
      - "traefik.http.routers.vw.tls.certresolver=letsencrypt"
      - "traefik.http.services.vw.loadbalancer.server.port=80"

volumes:
  vw-data:

networks:
  proxy:
    external: true

Два аспекта этого файла определяют всю архитектуру. Здесь отсутствует маппинг ports:, поэтому Vaultwarden доступен только через Traefik и его TLS; публикация порта на хосте — это то, как пользователи случайно открывают доступ к хранилищу по протоколу http. Значение DOMAIN должно быть полным публичным HTTPS URL: оно встраивается в ссылки на вложения, WebAuthn 2FA и эндпоинт уведомлений, поэтому неверное или http-значение нарушит их работу, даже если сайт загружается. Тег latest является намеренным исключением из обычного правила «никогда не используйте latest»: Vaultwarden выпускает свои стабильные релизы как единый rolling-образ, а :testing является отдельным каналом предварительных версий, поэтому обновляйтесь осознанно и просматривайте примечания к релизу перед выполнением pull. Однако это исключение узкое: большинство долгоживущих контейнеров лучше фиксировать на конкретном теге, что делает агент, работающий на том же VPS, предсказуемым при перезагрузках и обновлениях.

Запустите проект и следите за логом:

docker compose up -d
docker compose logs -f vaultwarden

Корректный запуск завершается строкой вида Rocket has launched from http://0.0.0.0:80. Дайте Traefik несколько секунд на получение сертификата, затем откройте https://vault.example.com; вы должны увидеть веб-хранилище Bitwarden с действительным значком замка и без предупреждений о сертификате.

Шаг 3: надежный ADMIN_TOKEN и ловушка с символом $

ADMIN_TOKEN защищает /admin — панель, которая имеет доступ ко всем пользователям и настройкам вашего экземпляра, поэтому относитесь к нему как к паролю root. Существует два способа его настройки.

Простой вариант — это случайная строка, которую вы уже сгенерировали с помощью openssl rand -base64 48. Поскольку base64 никогда не содержит $, она без проблем вставляется в .env без экранирования.

Более безопасный вариант — это хеш Argon2 PHC, при котором открытый текст токена никогда не сохраняется на диске. Сгенерируйте его с помощью того же образа:

docker run --rm -it vaultwarden/server /vaultwarden hash --preset owasp

Система дважды запросит ввод и выведет строку, начинающуюся с $argon2id$v=19$.... Вот ловушка, на которую люди тратят час: Docker Compose воспринимает $ как интерполяцию переменных, поэтому, если вы вставляете хеш напрямую под environment: в файле Compose, вы должны удвоить каждый $ до $$. Использование кавычек для значения допустимо; важно именно экранирование:

    environment:
      ADMIN_TOKEN: $$argon2id$$v=19$$m=19456,t=2,p=1$$c29tZXNhbHQ$$RdescudvJCsgt3ub+b+dWRWJTmaaJObG

Если вы предпочитаете хранить хеш в .env, правило меняется: оставьте одинарные знаки $, заключите всё значение в одинарные кавычки (ADMIN_TOKEN='$argon2id$v=19$...'), и существующая строка ${ADMIN_TOKEN} в файле Compose подхватит его. Никогда не удваивайте $ в .env. Если вы оставите одинарные знаки $ в самом файле Compose, Compose выдаст предупреждение The "argon2id" variable is not set и обнулит токен, после чего /admin отклонит ваш верный пароль. Запустите docker compose up -d и сохраните открытый текст, который вы вводили в приглашении, в своем менеджере паролей.

Шаг 4, регистрация учетной записи и ограничение доступа

Используя SIGNUPS_ALLOWED: "true", откройте https://vault.example.com, нажмите Create account и зарегистрируйтесь, указав адрес электронной почты и надежный мастер-пароль. Мастер-пароль невозможно восстановить или сбросить, поэтому сначала сохраните его в надежном месте.

Теперь ограничьте доступ. Отредактируйте файл Compose, чтобы отключить регистрацию:

      SIGNUPS_ALLOWED: "false"

Примените изменения с помощью docker compose up -d. Это обязательная мера безопасности, которую нельзя откладывать. Если оставить регистрацию открытой, любой пользователь или поисковый робот, обнаруживший URL, сможет создать учетную запись на вашем сервере. Они не получат доступ к вашему хранилищу, но будут потреблять ресурсы и превратят ваш приватный экземпляр в публичный сервис. Признак того, что регистрация осталась включенной: в /admin появятся учетные записи, которые вы не создавали.

Чтобы добавить членов семьи или коллег позже, не открывая публичную регистрацию, используйте кнопку Invite User в /admin. Для работы этого способа необходимо настроить SMTP, чтобы приглашенный пользователь получил ссылку.

Шаг 5, доступ к /admin

Перейдите по адресу https://vault.example.com/admin и введите административный токен в открытом виде (случайную строку или пароль, который вы хешировали, а не сам хеш). Внутри вы можете просматривать список пользователей, изменять настройки, отправлять тестовое письмо и создавать снимки базы данных.

Если вместо страницы отображается The admin panel is disabled, please configure the 'ADMIN_TOKEN' variable to enable it, значит ADMIN_TOKEN пуст или не задан, что полностью отключает панель управления — это допустимый вариант, если она вам не нужна. Если страница загружается, но отклоняет токен, ознакомьтесь с ловушкой экранирования $$ в списке ошибок ниже. Забыли токен? Процедуры восстановления не предусмотрено; отредактируйте .env или файл Compose, установите новый токен и выполните docker compose up -d.

Шаг 6, подключение клиентов Bitwarden

Любой официальный клиент поддерживает работу с self-hosted сервером. Установите десктопное, мобильное или браузерное приложение Bitwarden из стандартных магазинов; специальная сборка Vaultwarden не требуется.

Перед входом в систему откройте настройки (значок шестеренки) на экране авторизации (пункт Self-hosted или Region → Self-hosted), укажите в поле Server URL адрес https://vault.example.com и сохраните изменения. Затем войдите, используя email и мастер-пароль, которые вы зарегистрировали ранее; клиент должен немедленно подключиться и предложить сохранение или автозаполнение учетных данных.

Если клиент выдает ошибку This is not a recognized Bitwarden server. You may need to check with your provider or update your server., значит, URL указан неверно, используется протокол http или сертификат не является доверенным. Сначала убедитесь, что страница https://vault.example.com корректно открывается в браузере. Задержки при обновлении данных на других устройствах связаны с работой WebSocket push, этот вопрос рассматривается ниже.

Шаг 7: создание jail в Fail2ban для эндпоинта авторизации

Vaultwarden записывает каждую неудачную попытку входа в файл, указанный в LOG_FILE, что идеально подходит для защиты от брутфорса. Если Fail2ban еще не установлен, инструкции по установке и базовой настройке можно найти в руководстве по защите SSH с помощью Fail2ban; здесь мы добавим один jail для Vaultwarden.

Сначала определите путь к именованному тому на хосте, чтобы Fail2ban мог прочитать лог:

docker volume inspect vaultwarden_vw-data --format '{{ .Mountpoint }}'

Эта команда выведет путь вида /var/lib/docker/volumes/vaultwarden_vw-data/_data; файл лога находится по адресу vaultwarden.log внутри него. Создайте фильтр:

# /etc/fail2ban/filter.d/vaultwarden.conf
[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$
ignoreregex =

И jail:

# /etc/fail2ban/jail.d/vaultwarden.local
[vaultwarden]
enabled   = true
filter    = vaultwarden
logpath   = /var/lib/docker/volumes/vaultwarden_vw-data/_data/vaultwarden.log
banaction = iptables-allports
chain     = DOCKER-USER
maxretry  = 5
findtime  = 600
bantime   = 3600

Перезагрузите конфигурацию командой sudo systemctl restart fail2ban и проверьте статус с помощью sudo fail2ban-client status vaultwarden.

Три особенности Docker определяют эффективность этой защиты. Во-первых, если в логах при каждой неудачной попытке отображается IP: 127.0.0.1 или IP-адрес вашего прокси, значит, Vaultwarden блокирует сам прокси. Установите IP_HEADER в значение заголовка, который реально передает ваш прокси (X-Forwarded-For для Traefik, X-Real-IP для блока nginx выше, CF-Connecting-IP при использовании Cloudflare). Начиная с версии 1.37.4, с помощью X-Forwarded-For Vaultwarden выбирает самый правый IP-адрес, который не входит в IP_HEADER_TRUSTED_PROXIES (по умолчанию local, что охватывает прокси на том же хосте или в той же сети Docker). Если перед вашим прокси находится CDN, добавьте его адреса в этот список. Во-вторых, выбор цепочки iptables зависит от вашего прокси: если Traefik запущен как контейнер с опубликованными портами, трафик проходит через путь FORWARD в Docker, поэтому блокировка должна выполняться в DOCKER-USER, как показано выше. Однако, если вы выбрали вариант с host-nginx из шага 1, соединения завершаются на nginx в цепочке INPUT хоста, и блокировка DOCKER-USER их не увидит. В этом случае удалите строку chain = DOCKER-USER, чтобы Fail2ban использовал стандартную цепочку INPUT. В-третьих, используйте banaction = iptables-allports вместо стандартной настройки по портам: этот jail не определяет порты, а блокировка по всем портам в DOCKER-USER надежно ограничивает доступ нарушителя ко всем опубликованным сервисам на сервере.

Шаг 8: резервное копирование хранилища и проверка восстановления

Том vw-data и есть ваш менеджер паролей. Он содержит db.sqlite3 (все записи), каталоги attachments/ и sends/, файлы rsa_key.* для подписи сессий входа и config.json из панели администратора. Резервная копия, в которой отсутствует хотя бы один из этих элементов, окажется бесполезной в нужный момент.

Копирование db.sqlite3 во время записи Vaultwarden может привести к получению поврежденного файла, поэтому делайте «холодный» снимок — простой займет всего несколько секунд:

#!/usr/bin/env bash
set -euo pipefail
STAMP=$(date +%F)
DEST=/root/vw-backups
VOL=$(docker volume inspect vaultwarden_vw-data --format '{{ .Mountpoint }}')
mkdir -p "$DEST"
docker compose -f /opt/vaultwarden/docker-compose.yml stop vaultwarden
tar czf "$DEST/vw-$STAMP.tgz" -C "$VOL" .
docker compose -f /opt/vaultwarden/docker-compose.yml start vaultwarden

Запускайте этот процесс через cron каждую ночь и копируйте .tgz за пределы сервера. Резервная копия, хранящаяся только на защищаемом сервере, не является полноценной. Надежный способ передачи данных — это ежедневное резервное копирование с помощью restic на другой сервер или в объектное хранилище, что обеспечивает шифрование архива и дедупликацию повторяющихся снимков. Кнопка Backup Database в панели администратора — это удобный способ создания «горячего» снимка только файла SQLite, но она не включает вложения и ключи.

Теперь выполните процедуру, которая отличает реальную резервную копию от теоретической: восстановите её один раз и убедитесь в работоспособности:

mkdir -p /tmp/vw-restore
tar xzf /root/vw-backups/vw-2026-07-15.tgz -C /tmp/vw-restore
docker run --rm -p 127.0.0.1:8888:80 -v /tmp/vw-restore:/data vaultwarden/server

С вашего ноутбука создайте туннель с помощью ssh -L 8888:127.0.0.1:8888 you@your-vps и откройте http://localhost:8888 (или http://127.0.0.1:8888). Поскольку адреса loopback считаются безопасным контекстом, crypto.subtle доступен, и хранилище расшифровывается через обычный http — это единственный тип адреса, где такое допустимо. Войдите под своим мастер-паролем и убедитесь, что все записи на месте. Если это так, значит, база данных, ключи RSA и мастер-пароль успешно проходят цикл восстановления, и вы сможете развернуть систему на новом VPS за считанные минуты. Остановите контейнер с помощью Ctrl-C и удалите /tmp/vw-restore. Используйте этот метод туннелирования для любого другого административного интерфейса на сервере, который не должен быть доступен из Интернета; именно так вы сможете получить доступ к самостоятельно развернутому сканеру безопасности open-kritt на порту 5173.

Типичные ошибки и сообщения, которые вы увидите

Cannot read properties of undefined (reading 'importKey') в консоли браузера. Хранилище было загружено по протоколу http, поэтому crypto.subtle не определено; обращайтесь к нему только через https:// и добавьте редирект с HTTP на HTTPS на стороне прокси.

This is not a recognized Bitwarden server... в клиенте. Указан URL сервера с http, допущена опечатка или сертификат не является доверенным; убедитесь, что https://vault.example.com отображает корректный значок замка, затем повторно введите адрес в настройках self-hosted клиента.

/admin отклоняет верный пароль. Хэш Argon2 потерял экранирование, каждый $ должен быть записан как $$ в файле Compose (но одиночный $ внутри одинарных кавычек в .env), либо вы ввели сам хэш вместо открытого текста, который он представляет.

Медленная синхронизация между устройствами; в консоли WebSocket connection to 'wss://vault.example.com/notifications/hub' failed. Прокси не передает заголовки Upgrade/Connection; Traefik делает это автоматически, для nginx необходимо добавить две строки upgrade из шага 1. Хранилище продолжает работать, но синхронизация происходит только при открытии. Старый выделенный порт 3012 больше не используется начиная с версии v1.31.0, поэтому отдельный маршрут для WebSocket не требуется.

Fail2ban сообщает о блокировке, но атакующий продолжает подключаться. Блокируется 127.0.0.1 из-за неверного IP_HEADER, либо блокировка попадает не в ту цепочку iptables; настройте chain = DOCKER-USER и banaction = iptables-allports.

Обновления

Загрузите новый образ и пересоздайте контейнер; именованный том и все ваши данные сохранятся:

docker compose pull
docker compose up -d

Vaultwarden выпускает обновления часто. Следите за заметками о релизах проекта, а не фиксируйте конкретную версию патча, так как некоторые релизы содержат инструкции по миграции. Перед любым мажорным обновлением сделайте свежую резервную копию; вы сможете выполнить откат, восстановив архив tarball в новый том.

FAQ

Является ли Vaultwarden тем же самым, что и Bitwarden?

Это совместимый независимый сервер, а не официальный продукт. Vaultwarden перереализует API сервера Bitwarden на языке Rust, поэтому все официальные клиенты для рабочего стола, мобильных устройств, браузеров и CLI работают с ним, потребляя при этом значительно меньше ресурсов, чем официальный стек. Формат хранилища идентичен, поэтому вы можете мигрировать в любом направлении с помощью экспорта и импорта данных.

Действительно ли мне нужен HTTPS или можно запустить его по http в локальной сети?

HTTPS необходим для всего, кроме тестирования через loopback. Веб-хранилище Bitwarden и расширения используют Web Crypto API браузера, который доступен только в защищенном контексте, поэтому при использовании обычного http клиент выдает Cannot read properties of undefined и не выполняет вход. Единственные адреса http, которые работают — это адреса loopback, такие как http://localhost или http://127.0.0.1, именно поэтому для теста восстановления в шаге 8 используется SSH-туннель.

Как запретить посторонним регистрироваться на моем сервере?

Установите SIGNUPS_ALLOWED: "false" в файле Compose и выполните docker compose up -d сразу после создания собственной учетной записи. После этого добавляйте новых пользователей через кнопку Invite User в /admin, для чего потребуется настроенный SMTP, чтобы они могли получить ссылку-приглашение. Периодически проверяйте список администраторов, чтобы убедиться, что не появилось неожиданных учетных записей.

Как создать резервную копию хранилища Vaultwarden?

Остановите контейнер на короткое время и заархивируйте весь том vw-data, db.sqlite3, attachments/, sends/, config.json и файлы rsa_key.*, затем скопируйте архив с сервера, желательно по ночному расписанию cron. Копирование работающего файла SQLite во время функционирования сервера создает риск получения поврежденного снимка, поэтому выполняйте копирование «на холодную». Самое важное — один раз восстановите данные в тестовый контейнер и войдите в систему, чтобы убедиться в работоспособности резервной копии, прежде чем полагаться на нее.

Безопасно ли хранить пароли на собственном сервере?

Да, если вы выполняете три условия, описанные в этом руководстве: использование настоящего HTTPS, закрытая регистрация с сильным токеном администратора и проверенные резервные копии. Ваше хранилище шифруется на стороне клиента с помощью мастер-пароля, поэтому даже сервер никогда не видит ваши пароли в открытом виде, а украденный файл db.sqlite3 не позволит прочитать записи без него. Тем не менее, он содержит адреса электронной почты учетных записей и «соленый» хеш, полученный из каждого мастер-пароля, который злоумышленник может попытаться взломать в офлайне, поэтому защищайте файл базы данных и каждую его копию. Платой за это является то, что установка обновлений и резервное копирование теперь лежат на вас, поэтому Fail2ban и процедура восстановления здесь обязательны. Как только они будут настроены, более детальный разбор векторов атак на self-hosted хранилище станет полезным следующим шагом, так как при шифровании самих записей на стороне клиента защищать остается только токен администратора и архив резервной копии.