Привет, Хабр! История стара как мир: сначала у тебя один пет-проект, потом второй, потом подворачивается фриланс… и вот ты уже тонешь в море из десятков паролей. Логины, ключи API, доступы к базам данных — всё это начинает жить своей жизнью в заметках, текстовых файлах и, о ужас, в памяти.
В какой-то момент я понял, что мой "зоопарк" паролей стал неуправляем. А мысль, что вся эта цифровая сокровищница лежит на серверах очередной "бесплатной" корпорации, начала немного напрягать. Нет, я не параноик, но идея полного контроля над своими самыми чувствительными данными показалась мне чертовски привлекательной.
Так начался мой путь к созданию собственной "крепости" для паролей. Путь, на котором я, конечно же, собрал несколько болезненных "граблей". Эта статья — выжимка моего опыта, чтобы вы могли построить свою крепость правильно с первого раза.
Герой нашего времени: Bitwarden или Vaultwarden?
Первым делом я посмотрел в сторону Bitwarden. Это open-source, у него отличные клиенты под все платформы, и его можно поднять на своём сервере. Идеально? Почти. Когда я открыл мануал по установке официального сервера, я немного приуныл. Он написан на .NET и тащит за собой целую вереницу контейнеров и MSSQL. Для моего скромного VPS, где крутятся пет-проекты, это было явным перебором.

И тут на сцену выходит Vaultwarden (раньше он назывался bitwarden_rs). Это неофициальная реализация сервера Bitwarden, написанная на Rust. И это, друзья, просто магия.
Он легковесный. Серьёзно, он работает в одном крошечном Docker-контейнере и потребляет в состоянии покоя смешные 10-15 МБ оперативной памяти.
Он простой. Установка занимает буквально 5 минут.
-
Он щедрый. Это ключевое преимущество: Vaultwarden бесплатно отдает фичи, за которые в официальной версии Bitwarden просят денег. Сюда входят:
Организации с коллекциями и группами для шеринга паролей.
Продвинутые виды 2FA, включая YubiKey, FIDO2 WebAuthn и Duo.
Экстренный доступ и многое другое.
Для начинающих сисадминов и разработчиков с домашними серверами выбор очевиден. Мы не хотим тратить ресурсы нашего сервера на тяжеловесного монстра, нам нужна быстрая и эффективная рабочая лошадка.
Поднимаем крепость: как не наступить на мины в конфиге
Изначально я скопировал простейший конфиг из интернета. Он работал, но, как я понял позже, в нём было заложено две мины замедленного действия. На Хабре за такое справедливо сжигают. Давайте сразу сделаем хорошо.
Мина №1: Тег latest. Мой первый конфиг содержал строку image: vaultwarden/server:latest. Это самая большая ошибка. latest сегодня и latest завтра — это два совершенно разных образа. Обновление может прилететь в любой момент и всё сломать. (Да, осознаю что может быть спорным решением - дочитайте до конца!)

Мина №2: Отключение регистрации через конфиг. Идея "запусти, зарегистрируйся, потом поправь конфиг" — ужасна. Это классический человеческий фактор. Забудешь — и твой сервер превратится в проходной двор. Правильный путь: Использовать админ-панель.
Правильный docker-compose.yml для вашей крепости
Вот конфиг, который учитывает все грабли и лучшие практики.
Главный лайфхак: Мы не будем использовать стандартный порт 8080. Давайте сразу выберем менее популярный, например 8833. Это как поселиться не на центральной площади, а в тихом переулке по соседству — спокойнее и надежнее.
# Создаем папку для проекта
mkdir ~/vaultwarden && cd ~/vaultwarden
# Создаем файл docker-compose.yml
touch docker-compose.yml
# Зайдем в режим редактирования
docker-compose.yml
Скопируйте это в docker-compose.yml и обязательно поменяйте vault.your-domain.com и значение ADMIN_TOKEN.
# /home/user/vaultwarden/docker-compose.yml
version: '3'
services:
vaultwarden:
# МИНА ОБЕЗВРЕЖЕНА: Жестко фиксируем версию!
# На 12 июля 2025 года актуальная версия 1.34.1
image: vaultwarden/server:1.34.1
container_name: vaultwarden
restart: unless-stopped
volumes:
- ./data:/data
ports:
# МИНА №3 ОБЕЗВРЕЖЕНА: Используем неко-конфликтный порт!
# Внутренний порт контейнера (80) связывается с портом 8833 на хосте.
# Nginx будет обращаться именно к 8833.
- 127.0.0.1:8833:80
environment:
DOMAIN: "https://vault.your-domain.com"
# МИНА ОБЕЗВРЕЖЕНА: Устанавливаем токен для доступа к админке.
ADMIN_TOKEN: 'your_super_secret_admin_token_here'
Лайфхак: Чтобы сгенерировать хороший токен прямо в консоли, используйте команду: openssl rand -base64 48.
Пример сгенерированной строки: Pxs5M1ojgVo1DTK2Z/zQ4X45fFgmjuPPy71xB15B+2R6QdVtM10VKnv/TRWasjO1
Ставим охранника: HTTPS — это маст-хэв
Я настроил HTTPS, получил заветный зеленый замочек в браузере и поначалу успокоился. Но, как оказалось, я просто запер парадную дверь, оставив все окна нараспашку.
Nginx: «Дверь на замке, окна нараспашку»

Nginx: Фундамент для крепости
Сначала мы построим "фундамент" для нашего охранника Nginx — минимальную конфигурацию, достаточную для того, чтобы Let's Encrypt убедился, что домен действительно наш.
Для начала создадим и откроем файл конфигурации Nginx:
sudo nano /etc/nginx/sites-available/vault.your-domain.com
Вставьте туда этот временный, минимальный конфиг. Не забудьте заменить vault.your-domain.com на свой домен.
server {
listen 80;
server_name vault.your-domain.com;
# Указываем стандартную папку, куда certbot положит файл для проверки
root /var/www/html;
}
Теперь "включаем" наш сайт и проверяем, что в конфиге нет ошибок:
# Создаем символическую ссылку, чтобы Nginx "увидел" наш конфиг
sudo ln -s /etc/nginx/sites-available/vault.your-domain.com /etc/nginx/sites-enabled/
# Проверяем синтаксис Nginx
sudo nginx -t
# Если проверка прошла успешно (видим "syntax is ok" и "test is successful"), перезагружаем Nginx
sudo systemctl reload nginx
Получаем SSL-сертификат с помощью Certbot
Теперь, когда фундамент готов, запускаем "строителя" — certbot. Он автоматически получит SSL-сертификат и, что самое главное, сам перепишет наш конфиг, добавив туда всё необходимое для работы HTTPS.
# Устанавливаем certbot и плагин для Nginx (для Debian/Ubuntu)
sudo apt update && sudo apt install certbot python3-certbot-nginx -y
# Запускаем certbot для нашего домена
sudo certbot --nginx -d vault.your-domain.com
Certbot задаст пару вопросов, включая ваш e-mail для уведомлений и согласие с условиями. В конце он спросит, нужно ли делать автоматический редирект с HTTP на HTTPS — обязательно выберите вариант 2 (Redirect).
Возводим стены: добавляем заголовки безопасности
Вот мы и подошли к ключевому моменту, где я ошибался раньше. Certbot отлично настроил SSL, но он понятия не имеет, что мы хотим перенаправлять трафик на Vaultwarden. Он просто взял наш "фундамент" и прикрутил к нему SSL.
Поэтому сейчас мы выступим в роли инженера, который доводит работу автоматики до ума.
Шаг 1: Открываем то, что нам сгенерировал Certbot
sudo nano /etc/nginx/sites-available/vault.your-domain.com
Шаг 2: Получаем сертификат (безопасным способом)
Теперь запускаем Certbot в режиме certonly. Он не будет трогать наши конфиги.
-
Установите Certbot (если еще не установлен):
sudo apt update && sudo apt install certbot -y
-
Запустите получение сертификата, указав папку для проверки:
sudo certbot certonly --webroot -w /var/www/html -d vault.your-domain.com
Certbot задаст пару вопросов (email, согласие). Ответьте на них. Если все пройдет успешно, он сообщит, что сертификаты сохранены.
Шаг 3: Возводим финальную Крепость (Nuke & Pave)
Вот он, ключевой шаг. Мы не будем ничего редактировать. Мы полностью заменим наш временный конфиг на финальный, рабочий.
-
Откройте ваш файл конфигурации еще раз. Сотрите в нём всё до последней строчки.
sudo nano /etc/nginx/sites-available/vault.your-domain.com
-
Теперь вставьте туда этот полный, финальный, единственно правильный конфиг.
### НАЧАЛО БЛОКА ДЛЯ HTTPS (ПОРТ 443) ### server { listen 443 ssl http2; server_name vault.your-domain.com; # <-- ЗАМЕНИ НА СВОЙ ДОМЕН ### ПУТИ К СЕРТИФИКАТАМ, КОТОРЫЕ МЫ ТОЛЬКО ЧТО ПОЛУЧИЛИ ### ssl_certificate /etc/letsencrypt/live/vault.your-domain.com/fullchain.pem; # <-- ЗАМЕНИ ssl_certificate_key /etc/letsencrypt/live/vault.your-domain.com/privkey.pem; # <-- ЗАМЕНИ include /etc/letsencrypt/options-ssl-nginx.conf; # Эти файлы создает Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # Этот тоже ### НАШ "МОСТ" К VAULTWARDEN ### location / { # ВНИМАНИЕ: порт 8833 - тот самый, что мы указали в docker-compose! proxy_pass http://127.0.0.1:8833; 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; } } ### КОНЕЦ БЛОКА ДЛЯ HTTPS ### ### НАЧАЛО БЛОКА ДЛЯ HTTP (ПОРТ 80) - ОН НУЖЕН ТОЛЬКО ДЛЯ РЕДИРЕКТА ### server { listen 80; server_name vault.your-domain.com; # <-- ЗАМЕНИ НА СВОЙ ДОМЕН # Просто перенаправляем весь трафик на защищенную версию return 301 https://$host$request_uri; } ### КОНЕЦ БЛОКА ДЛЯ HTTP ###
Шаг 4: Последняя проверка
Сохраните файл и выполните финальную команду:
sudo nginx -t && sudo systemctl reload nginx
Почему этот способ лучше? Потому что он предсказуемый. Ты не редактируешь непонятно что, а полностью заменяешь временный файл на финальный, заведомо рабочий конфиг. Никаких случайных скобок и потерянных директив.
Закрываем ворота: настройка через админ-панель
Теперь, когда у нас есть правильный конфиг, последовательность действий проста и безопасна.
Запускаем контейнер: docker-compose up
Регистрируем свой аккаунт на https://vault.your-domain.com.
-
Сразу же закрываем регистрацию для всех остальных!
Открываем админ-панель: https://vault.your-domain.com/admin.
-
Вводим наш ADMIN_TOKEN.
Переходим во вкладку "General settings" и снимаем галочку "Allow new signups".
Нажимаем "Save".

Правило честного компромисса: теперь с осознанными обновлениями
Self-host — это круто, но это и ответственность.
Вы сами отвечаете за бэкапы. Потеряете данные с диска — потеряете пароли. Сделайте бэкап, или однажды будете горько плакать. Самый простой способ — остановить контейнер и заархивировать всю вашу папку ~/vaultwarden.
Вы сами отвечаете за обновления. Лайфхак: Раз в месяц-два заходите на страницу релизов Vaultwarden на GitHub, читайте описание новых версий (changelog) и, если всё в порядке, меняйте номер версии в docker-compose.yml и выполняйте docker-compose up -d --force-recreate. Это и есть осознанное обновление.
Куда бежать, если что-то сломалось? Помните: проблемы с клиентами (Android, iOS, браузер) — это к Bitwarden. Проблемы с сервером — к Vaultwarden.
Я прошел этот путь и наступил на самые очевидные мины, чтобы вы не повторили моих ошибок. Теперь вы можете построить не просто работающую, а по-настоящему надежную и безопасную крепость для своих паролей. Это дарит не только безопасность, но и приятное чувство уверенности в своих силах.
А теперь вопрос к вам, сообщество: как вы подходите к обновлениям своих self-hosted сервисов? Пинните версии, как параноики (вроде меня), используете latest и надеетесь на лучшее, или у вас есть автоматизированные системы для тестирования и выкатки обновлений? Делитесь своими стратегиями в комментариях.
Комментарии (10)
nv13
15.07.2025 08:26А потом vps ка по какой то из причин станет недоступной и всё.
andreymal
15.07.2025 08:26Клиенты хранят локальную копию базы, если сервер отвалится - неприятно, но не катастрофа, доступ к паролям не потеряется
Nill-Ringil
15.07.2025 08:26У меня Vaultwarden работал в двух копиях
На VPS
У меня дома на RPi
Между ними синхронизация syncthing, домашняя копия доступна через cloudflared, все красиво
И по какой-то причине(ордер на обыск и изъятие в рамках ОРМ по «гос.измена») стал недоступен именно домашний инстанс, а инстанс на VPS прекрасно все пережил, дождался когда я смог бежать с россии и радостно приветствовал меня в новой стране
Так что практика показала, что менее живучая та копия, которая у тебя дома на твоем железе, а копия на VPS если все оплачено спокойно переживает что угодно
m1skam
15.07.2025 08:26Главный лайфхак: Мы не будем использовать стандартный порт 8080. Давайте сразу выберем менее популярный, например 8833. Это как поселиться не на центральной площади, а в тихом переулке по соседству — спокойнее и надежнее.
Я искренне не понимаю этот "лайфхак" и почему он главный. Особенно в контексте обратного прокси на nginx.
c46fd3da
Выставлять свой менеджер паролей голой задницей в интернет не самое мудрое решение.
И если уж выставлять, то с использованием абстрактного субдомена, который не угадать, и через wildcard сертификат, чтобы на crt.sh не засветился он.
Все остальное IMHO это игра с огнем.
natane
>через wildcard сертификат, чтобы на crt.sh не засветился он.
Можете расшифровать для людей, далёких от администрирования?
c46fd3da
На ресурсе https://crt.sh доступны списки выданных сертификатов.
Чтобы субдомен там не светить надо пользоваться wildcard сертификатами и получать их через acme dns например.