Как мы ушли от паролей в Google Docs: разворачиваем Passbolt на своём VPS
Пошаговая инструкция по развёртыванию Passbolt — self-hosted менеджера паролей с открытым кодом — на собственном VPS. Покупка домена, Docker Compose, Nginx Proxy Manager с Let's Encrypt, бэкапы, безопасность. Альтернативы Cloudflare для пользователей из РФ.
В одной из команд, где я работал, пароли жили в Google Docs. Документ назывался что-то вроде пароли_не_смотреть, доступ к нему был у всех, кто когда-либо его открывал, история изменений — на совести Google. Когда сотрудник уходил, никто толком не знал, какие именно пароли надо ротировать: проще было поменять всё подряд или забить и надеяться.
Эту дыру надо было как-то закрывать. Дальше — как я выбирал решение, во что в итоге упёрся и как развернул Passbolt у себя для семьи (по той же схеме, что подходит и для небольшой команды).
Что я смотрел перед Passbolt
Passwork. Первое, с чем я познакомился вживую — отличный функционал, удобные группы, аудит, мобильные клиенты. Но цена для небольшой команды или семьи плохо бьётся с задачей: платить корпоративный ценник за 4–6 человек не хочется.
1Password, LastPass, Bitwarden (облако). Закрывают сценарий «храни и шарь», но всё хранится на чужих серверах. Для семьи это приемлемо, для команды с реальными доступами к проду — уже вопрос доверия и compliance.
Vaultwarden. Self-hosted реализация Bitwarden API. Лёгкий, поднимается в один контейнер, поддерживает не только пароли, но и данные карт. Хороший вариант, если знаешь, что ограничишься личным использованием или маленькой группой без жёстких ролей.
Passbolt CE. Open-source, self-hosted, с акцентом именно на командную работу: группы, права на конкретный секрет, видно — кому, когда и какой доступ был выдан. То, что нужно, когда уход сотрудника не должен превращаться в массовую ротацию паролей.
Изначально я искал решение для компании — закрыть ту самую дыру с Google Docs. Passbolt подошёл: бесплатный, self-hosted, с группами и аудитом, не упирающийся в корпоративный ценник. А когда понадобилось организовать пароли уже дома — для семьи — развернул его же по той же схеме. Дальше — про развёртывание под домашний сценарий, но архитектура один в один масштабируется на команду: меняются только пользователи и группы.
Кому подойдёт эта инструкция
- Есть домашняя лаба или опыт с Docker
- Нужно расшаривание с ролями и аудитом — в семье, в небольшой команде или в pet-проекте
- Важно видеть: кому, когда, какой доступ был выдан
Если речь про одного человека — Bitwarden или Vaultwarden закроют задачу с меньшими хлопотами.
1. Покупаем домен
Регистратор — на свой вкус. Я использую reg.ru (рефералка: код 9E45-4577-1048-A828 даёт скидку).
Что важно при выборе зоны:
- Смотреть на цену продления, а не на цену первого года. В бюджетных зонах вроде
.online,.store,.fun,.icuстартовая цена часто символическая, но продление в разы выше. На некоторых зонах (например,.pro) бывает обратная ситуация — стабильно дёшево и при покупке, и при продлении. Стоит сравнить несколько зон в корзине прежде чем оплачивать. - Дом или работа. Для домашнего сервиса подойдёт любая дешёвая зона. Для рабочего — лучше
.ruили.com: некоторые корпоративные DNS-фильтры режут «мусорные» зоны и сотрудники просто не смогут открыть менеджер паролей с офисной сети. - Имя домена — рандом vs говорящее. Менеджер паролей — это не сайт-визитка, его не нужно запоминать наизусть: один раз сохранил закладку и всё. Чем менее говорящее имя, тем меньше информации утекает наружу:
passwords-mycompany.ruсразу сообщает атакующему, что по этому адресу живёт чувствительный сервис, а условныйkx7m2.online— нет. Это небольшой дополнительный слой — не панацея (через DNS-логи и Certificate Transparency сервис всё равно найдут, если будут искать целенаправленно), но и не лишний.
Ловушка с двумя доменами. Reg.ru на оформлении предложит докинуть второй домен за символическую цену — выглядит как подарок, но продление второго обычно сильно дороже. Если второй домен реально не нужен — отказаться.


2. VPS или домашнее железо?
Passbolt можно развернуть как на арендованном VPS, так и на домашнем сервере/мини-ПК/Raspberry Pi. Оба варианта рабочие, но у домашнего есть требование, без которого ничего не заработает: белый статический IP.
- Белый (публичный) — потому что Passbolt должен быть доступен снаружи: с телефона по дороге домой, с рабочего ноутбука, из браузерного расширения у родственников. Если провайдер выдаёт серый IP за NAT — снаружи на этот адрес попасть нельзя.
- Статический — потому что DNS-запись A
your-domain.online → IPдолжна стабильно указывать на один и тот же адрес. Динамический IP технически можно обернуть в DDNS, но это лишняя точка отказа в сервисе, от которого зависит вход во все остальные.
У большинства российских провайдеров белый статический IP — платная опция, обычно в пределах нескольких сотен рублей в месяц. Если IP за NAT и менять условия с провайдером не вариант — можно пробросить трафик через туннель на внешний VPS (Wireguard/Tailscale + reverse proxy), но это уже отдельная история и заметное усложнение схемы.
Дальнейшая инструкция написана под аренду VPS — у него белый статический IP «из коробки» и не нужно думать о провайдерских условиях. Если хочется поставить на домашнее железо — все шаги, начиная с Docker, идентичны, меняется только то, куда указывает A-запись домена.
Берём самый бюджетный тариф на VDSina — для Passbolt хватит 1 ядра и 1 ГБ ОЗУ. Лично пользуюсь этим хостером уже пару лет, оправдывает свои деньги (бывают сбои, но проблемы не задерживались дольше пары дней).
Рекомендация: не жадничать на месте и взять хотя бы 50 ГБ — это избавит от необходимости частой очистки логов, а стоимость вырастет несильно.


3. Доменные записи и прятки за прокси
Изначально в этой статье использовался Cloudflare: бесплатно, удобно, дополнительно скрывает реальный IP сервера. С 9 июня 2025 года российские провайдеры начали активно резать трафик до сетей Cloudflare (Cloudflare о ситуации в РФ). На стороне самого Cloudflare решения нет — это действия local ISP. Для сервиса, которым нужно стабильно пользоваться из России, Cloudflare больше не вариант.
Дальше — два сценария, выбирать по ситуации.
Вариант A. Без CDN-прокси (рекомендую для домашнего сценария)
Если читатель и его семья/команда находятся в РФ — проще всего обойтись без CDN-прослойки. A-запись напрямую указывает на IP VPS, HTTPS закрывается через Nginx Proxy Manager + Let's Encrypt (см. шаги 6–7).
- Плюсы: работает стабильно, не требует обходных манёвров.
- Минусы: реальный IP сервера виден. Атакующие сканируют интернет массово и постоянно — сам факт «у вас есть VPS» секретом не является. Что важно: рандомное имя домена не светится публично, сервис закрыт логином и PGP-фразой, на сервере оставлены только нужные порты (см. шаг 9). Этого достаточно для домашнего сценария.
Что делать: в панели регистратора или DNS-провайдера создать A-запись your-domain.online → <IP вашего VPS>.
Вариант B. С CDN/прокси
Если хочется дополнительного слоя (скрыть IP, базовая DDoS-защита, кеширование), есть несколько путей — у каждого свои оговорки:
- Российские CDN (Selectel, NGENIX, DDoS-Guard, StormWall) — работают стабильно в РФ, но тарифы рассчитаны на бизнес и стартуют от нескольких тысяч рублей в месяц. Для домашнего Passbolt это перебор по цене.
- Cloudflare с обходом блокировок на стороне клиента (WARP, VPN, прописывание Cloudflare-IP в hosts) — технически возможно, но превращает «бесплатное удобное решение» в «надо настроить обход у каждого члена семьи и поддерживать это». Если кто-то из пользователей не в РФ — у него Cloudflare работает обычным образом.
- Self-hosted прокси на втором VPS за рубежом — для энтузиастов. Отдельная статья.
Дальше инструкция идёт по Варианту A.
4. Устанавливаем Docker
Команды ниже взяты из официального гайда Docker для Ubuntu — для другого дистрибутива стоит свериться там же, инструкция может разойтись.
Добавляем официальный репозиторий Docker:
# GPG-ключ
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Репозиторий
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
Устанавливаем сам Docker и плагин Compose (он понадобится, чтобы поднимать Passbolt и Nginx Proxy Manager):
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Проверяем, что всё встало:
sudo docker run --rm hello-world
Если в выводе появилось Hello from Docker! — Docker работает.
В этой инструкции все командыdockerдалее идут черезsudo— так надёжнее: не нужно думать о членстве в группах и правах доступа. Альтернатива — добавить пользователя в группуdocker(тогдаsudoне нужен), но членство в этой группе фактически равно правам root на хосте: Docker умеет монтировать любые директории. Если охота сократить наборsudo— можно сделать это осознанно, в остальных случаях проще оставить как есть.
5. Docker Compose для Passbolt
Создаём рабочую директорию:
mkdir ~/passbolt && cd ~/passbolt
Секреты — в отдельный .env
Чтобы пароли и почтовые креды не лежали внутри docker-compose.yml, выносим их в .env. Так удобнее править и проще не закоммитить случайно в git.
Сгенерируем пароль для БД (24 байта, base64) и сразу запишем его в .env:
cat > .env <<EOF
DB_PASSWORD=$(openssl rand -base64 24)
APP_FULL_BASE_URL=https://your-domain.online
EMAIL_FROM=you@gmail.com
EMAIL_USER=you@gmail.com
EMAIL_PASSWORD=your-gmail-app-password
EOF
chmod 600 .env
Заполнить APP_FULL_BASE_URL своим доменом, EMAIL_* — почтой, которая будет отправлять письма пользователям (приглашения, восстановление). Для Gmail нужен app password, не основной пароль аккаунта — сгенерировать здесь (нужно включить 2FA).
chmod 600 ограничивает доступ к файлу только владельцем — обязательно, в файле лежат секреты.
docker-compose.yml
nano docker-compose.yml
services:
db:
image: mariadb:10.11
restart: unless-stopped
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "true"
MYSQL_DATABASE: "passbolt"
MYSQL_USER: "passbolt"
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- database_volume:/var/lib/mysql
passbolt:
image: passbolt/passbolt:latest-ce
restart: unless-stopped
depends_on:
- db
environment:
APP_FULL_BASE_URL: ${APP_FULL_BASE_URL}
DATASOURCES_DEFAULT_HOST: "db"
DATASOURCES_DEFAULT_USERNAME: "passbolt"
DATASOURCES_DEFAULT_PASSWORD: ${DB_PASSWORD}
DATASOURCES_DEFAULT_DATABASE: "passbolt"
EMAIL_DEFAULT_FROM: ${EMAIL_FROM}
EMAIL_TRANSPORT_DEFAULT_HOST: smtp.gmail.com
EMAIL_TRANSPORT_DEFAULT_PORT: 587
EMAIL_TRANSPORT_DEFAULT_USERNAME: ${EMAIL_USER}
EMAIL_TRANSPORT_DEFAULT_PASSWORD: ${EMAIL_PASSWORD}
EMAIL_TRANSPORT_DEFAULT_TLS: "true"
PASSBOLT_SSL_FORCE: "false"
volumes:
- gpg_volume:/etc/passbolt/gpg
- jwt_volume:/etc/passbolt/jwt
command:
[
"/usr/bin/wait-for.sh",
"-t", "0",
"db:3306",
"--",
"/docker-entrypoint.sh",
]
ports:
- "127.0.0.1:40080:80"
- "127.0.0.1:40443:443"
volumes:
database_volume:
gpg_volume:
jwt_volume:
Что важно в этом конфиге:
127.0.0.1:40080:80— порт прибит к loopback, наружу не торчит. Passbolt доступен только с самого сервера; снаружи к нему будет ходить Nginx Proxy Manager в шаге 7. Это снимает целый класс атак: даже если в UFW случайно откроются порты, до Passbolt напрямую не достучаться.PASSBOLT_SSL_FORCE: "false"— это не значит, что HTTPS не используется. HTTPS терминируется на NPM (с настоящим сертификатом Let's Encrypt), а от NPM до Passbolt внутри сервера идёт обычный HTTP. Так делают почти все, кто ставит reverse proxy перед приложением.restart: unless-stopped— контейнеры поднимутся сами после ребута VPS.
Альтернатива: compose с официального сайта
На сайте Passbolt лежит официальный docker-compose-ce.yaml. Его можно взять как референс и адаптировать по тем же принципам (вынести секреты в .env, прибить порты к 127.0.0.1). Если идти этим путём, у официального файла есть три нюанса, на которые легко наступить:
1. Имя файла — docker-compose-ce.yaml, а не docker-compose.yml.
Стандартное sudo docker compose up -d без аргументов ищет только docker-compose.yml / docker-compose.yaml — официальный файл с суффиксом -ce оно не подхватит и выдаст «no configuration file provided». Два варианта:
# Вариант А: переименовать
mv docker-compose-ce.yaml docker-compose.yml
sudo docker compose up -d
# Вариант Б: каждый раз указывать файл явно
sudo docker compose -f docker-compose-ce.yaml up -d
sudo docker compose -f docker-compose-ce.yaml logs -f passbolt
Вариант А удобнее, если Passbolt — единственный сервис в этой папке. Вариант Б — если рядом лежат другие compose-файлы и важно не перепутать.
2. Имена контейнеров и volume'ов зависят от имени папки.
Docker Compose формирует имена так: <имя-папки>_<имя-сервиса>-<n> для контейнеров и <имя-папки>_<имя-volume> для томов. Если папка называется ~/passbolt/ — получится passbolt_passbolt-1 и passbolt_gpg_volume. Если папка ~/passbolt_docker/ (как часто оказывается после git clone) — будет passbolt_docker_passbolt-1 и passbolt_docker_gpg_volume.
На что это влияет:
- Бэкап-скрипт из шага 9 обращается к volume'ам по именам
passbolt_gpg_volume/passbolt_jwt_volume. Если префикс другой — нужно поправить имена в скрипте, иначе бэкап молча сохранит пустые архивы. - Команды
docker compose exec passbolt ...работают одинаково в обоих случаях, потому что обращаются к имени сервиса (passbolt), а не к имени контейнера. Так что инструкция по созданию первого пользователя из шага 8 не сломается.
Проверить актуальные имена:
sudo docker compose ps # имена контейнеров
sudo docker volume ls | grep gpg # имена volume'ов
3. Если хочется зафиксировать имена явно — добавить name: в начало compose-файла:
name: passbolt
services:
db:
...
Тогда префикс не будет зависеть от папки: всё будет называться passbolt_*, как в инструкциях ниже.
Запускаем
sudo docker compose up -d
sudo docker compose logs -f passbolt
Первое поднятие занимает 30–60 секунд: MariaDB инициализирует БД, Passbolt генерирует GPG-ключи сервера и накатывает миграции. Когда в логах появится строка вида Welcome to Passbolt! — контейнер готов.
Проверить, что Passbolt отвечает локально:
curl -I http://127.0.0.1:40080
Должен вернуть HTTP/1.1 302 или 200. Это значит, что приложение работает; снаружи оно пока недоступно — этим займётся NPM в шаге 7.
6. Nginx Proxy Manager
NPM — это reverse proxy на базе Nginx с веб-интерфейсом и автоматическим выпуском Let's Encrypt-сертификатов. Он будет принимать HTTPS-запросы снаружи на 443 порт и проксировать их на Passbolt.
Где запускать NPM: вместе с Passbolt или отдельно?
Вместе с Passbolt в одном compose — путь, описанный ниже. Подходит, если:
- это первая инсталляция и пока нет других сервисов, которые нужно проксировать;
- Passbolt стоит на отдельном VPS «под одну задачу»;
- хочется получить рабочий результат за один присест, без лишних развилок.
Отдельно от Passbolt — мой основной паттерн дома. NPM поднят как самостоятельный сервис и управляет трафиком всей домашней лабы: один прокси, одна точка терминации SSL, через который наружу пробрасывается только то, что должно быть наружу. Так логичнее, если:
- на сервере уже есть или будут другие сервисы (медиа, мониторинг, ещё что-то self-hosted);
- хочется явно отделить «инфраструктурный слой» (DNS, прокси, сертификаты) от «прикладного» (Passbolt, остальное).
Настройка NPM как самостоятельного сервиса — тема для отдельной заметки, тут на ней не останавливаюсь.
Для команды/прода — другой разговор. Если Passbolt разворачивается для рабочей команды, имеет смысл начать не с прикладного сервиса, а с обратного прокси: централизованный reverse proxy, политики безопасности, единая точка терминации SSL и логов. В корп-сценариях это часто уже есть (Traefik в Kubernetes-кластере, nginx-конфиги под управлением ansible, корпоративный WAF). Городить рядом ещё один NPM ради одного Passbolt — плохая идея: ломается единая модель управления трафиком, появляется второй слой, который никто не патчит. В таком случае ниже стоит читать как референс, чем эквивалентно настроить ваш существующий прокси (forward host, схема, websockets, заголовки).
Дальше — конфиг для сценария «всё в одном compose, для пробы и для дома».
Добавляем сервис в тот же docker-compose.yml
Чтобы Passbolt и NPM могли общаться по внутренним именам контейнеров (passbolt, db, npm), их удобнее держать в одном compose-файле. Открываем тот же ~/passbolt/docker-compose.yml и добавляем сервис рядом с db и passbolt:
npm:
image: 'jc21/nginx-proxy-manager:2'
restart: unless-stopped
ports:
- '80:80' # HTTP, нужен для Let's Encrypt http-01 challenge
- '443:443' # HTTPS
- '127.0.0.1:81:81' # админка — только локально, через SSH-туннель
volumes:
- ./npm-data:/data
- ./npm-letsencrypt:/etc/letsencrypt
Поднимаем:
sudo docker compose up -d
Что важно в этом конфиге:
jc21/nginx-proxy-manager:2— пин к мажорной версии 2.x. С:latestмажорное обновление может прилететь молча и поломать конфиг; с:2будут приходить только совместимые апдейты в рамках мажора. Обновляться на v3 (когда выйдет) — осознанно, после прочтения changelog.127.0.0.1:81:81— админка NPM не доступна снаружи. Это критично: её дефолтные кредыadmin@example.com / changeme— публичная информация, и боты ломятся в открытые 81 порты постоянно../npm-dataи./npm-letsencrypt— папки создадутся в~/passbolt/. Это конфиг NPM и сертификаты, их нужно будет включить в бэкап (см. шаг 9).
Как зайти в админку
Раз порт 81 прибит к loopback, напрямую с устройства открыть http://<ip>:81 не получится. Делаем SSH-туннель:
ssh -L 8081:127.0.0.1:81 user@your-vps-ip
После подключения админка NPM доступна на устройстве по http://localhost:8081. Туннель работает, пока открыт SSH-сеанс — закрыли терминал, доступ из браузера пропал.
Первый вход: логин admin@example.com, пароль changeme. NPM сразу попросит сменить почту и пароль — сменить немедленно, до того, как будут настроены прокси-хосты.
7. Настраиваем Proxy Host в NPM с Let's Encrypt
На этом шаге Passbolt станет доступен снаружи по HTTPS на своём домене.
Что должно быть готово к этому шагу
- В DNS у домена создана A-запись на IP VPS (шаг 3)
- Passbolt запущен и отвечает локально на
http://127.0.0.1:40080(шаг 5) - В NPM сменён дефолтный пароль (шаг 6)
- 80 и 443 порты на VPS открыты для входящих (на этом шаге UFW ещё не настроен, по дефолту они открыты; если уже закрыли — сначала открыть, иначе Let's Encrypt не пройдёт проверку)
Создаём Proxy Host
В админке NPM открываем вкладку Hosts → Proxy Hosts → Add Proxy Host.
Вкладка Details:
| Поле | Значение | Комментарий |
|---|---|---|
| Domain Names | your-domain.online |
без https://, без слэшей |
| Scheme | http |
от NPM до Passbolt внутри сети идёт HTTP, см. PASSBOLT_SSL_FORCE: false в шаге 5 |
| Forward Hostname / IP | passbolt |
имя контейнера из docker-сети, NPM резолвит его автоматически, потому что лежит в том же compose |
| Forward Port | 80 |
внутренний порт контейнера Passbolt, не 40080 |
| Block Common Exploits | ✅ | стандартный набор Nginx-правил против частых паттернов атак |
| Websocket Support | ✅ | Passbolt использует websocket-соединения |
Важно про порт: в шаге 5 наружу проброшен 127.0.0.1:40080 → 80, но NPM ходит к Passbolt не через хостовый loopback, а напрямую по docker-сети к контейнеру passbolt на его внутренний порт 80. Поэтому здесь именно 80, а не 40080.
Вкладка SSL:
| Поле | Значение |
|---|---|
| SSL Certificate | Request a new SSL Certificate |
| Force SSL | ✅ |
| HTTP/2 Support | ✅ |
| HSTS Enabled | ✅ |
| Email Address for Let's Encrypt | действующий ящик |
| I Agree to the Let's Encrypt Terms of Service | ✅ |
Жмём Save. NPM запросит сертификат у Let's Encrypt — занимает 10–60 секунд. По окончании в списке Proxy Hosts появится зелёный статус.
Проверка
С ноутбука открываем https://your-domain.online. Должна загрузиться страница установки Passbolt (если первый запуск) или экран входа. В адресной строке — замочек и валидный сертификат от Let's Encrypt.
Если что-то пошло не так
- Let's Encrypt не выпустил сертификат. Самая частая причина — A-запись домена не указывает на этот VPS (или указывает, но DNS ещё не разошёлся: дать 5–10 минут, проверить через
dig your-domain.online). Вторая — порт 80 закрыт на VPS или у провайдера. Too many redirectsили бесконечный редирект. В compose не выставленоPASSBOLT_SSL_FORCE: "false"— Passbolt сам пытается редиректить на HTTPS, а NPM уже его проксирует. Поправить в.envили compose и перезапустить:sudo docker compose up -d.502 Bad Gateway. Контейнер Passbolt ещё не поднялся (первое поднятие может занять до минуты — БД и GPG-ключи генерируются). Подождать, посмотреть логи:sudo docker compose logs -f passbolt.
8. Создаём первого пользователя
На свежей инсталляции у Passbolt нет публичной регистрации — это сделано специально, чтобы случайный человек, открыв URL, не стал первым админом. Первый пользователь создаётся командой внутри контейнера; команда печатает одноразовую ссылку, по которой админ доделывает регистрацию в браузере.
Создаём admin-юзера
sudo docker compose exec passbolt su -m -c \
"/usr/share/php/passbolt/bin/cake passbolt register_user \
-u admin@your-domain.online \
-f Admin \
-l User \
-r admin" -s /bin/sh www-data
Что в команде:
-u— email админа (на него потом будут приходить системные письма)-f/-l— first name / last name-r admin— роль; альтернативаuser(обычный пользователь без прав на админку)
На почту -u команда письма не отправляет — она печатает ссылку прямо в stdout. Выглядит примерно так:
https://your-domain.online/setup/install/<user-uuid>/<token>
Завершаем регистрацию в браузере
Открываем ссылку из вывода. Passbolt предложит:
- Установить браузерное расширение (для Chrome/Firefox). Без расширения работать не получится — оно держит локальный PGP-ключ и расшифровывает пароли на клиенте. Это и есть суть end-to-end шифрования: сервер видит только зашифрованные данные.
- Сгенерировать PGP-ключ. Passbolt сделает это сам прямо в браузере. Ключ привязан к этому admin-аккаунту.
- Задать passphrase. Это пароль, которым шифруется приватный PGP-ключ.
- Скачать recovery kit. Это резервная копия PGP-ключа админа в виде файла.
Про passphrase и recovery kit — ниже отдельно, это самые важные понятия во всей инсталляции.
Про passphrase
Passphrase — единственное, что защищает приватный PGP-ключ, и единственное, что нельзя восстановить. Никаких «забыли пароль?» в Passbolt нет: это не баг, а суть end-to-end шифрования.
Правила, которые работают:
- Запоминается. Парольная фраза из нескольких случайных слов на родном языке — надёжнее короткого «сложного» пароля и лучше держится в памяти. Достаточно трёх слов, если они действительно случайные и личные: дурацкая обзывалка друга, локальная семейная шутка, нелепая фраза, которую сказал ребёнок. То, что никто, кроме узкого круга, не угадает, а владелец не забудет.
- Используется часто. Если сервис лежит без дела, фраза забывается. В этом смысле обратное тоже верно: нет смысла в Passbolt, которым не пользуются. Если через полгода окажется, что в него никто не заглядывает — лучше снести и не страдать.
- Не сохраняется в браузере, в заметках, в облаке. Если passphrase лежит в Google Keep — вся конструкция бессмысленна: приватный ключ шифруется именно ею.
Что если passphrase всё же потеряна
Тут есть встроенное решение, и оно правильнее, чем «конверт у бабушки».
Заводим минимум двух админов. В Passbolt admin — это не только «может приглашать пользователей», но и носитель ресурсов, которые в случае потери одного аккаунта можно перевыдать остальным. Если жена/коллега тоже admin со своими PGP-ключом и passphrase — при потере доступа у одного из вас второй пересоздаст аккаунт и перешарит общие пароли.
Это не «второй ключ от того же замка» — это два независимых полноценных аккаунта, которыми семья реально пользуется. Никаких конвертов и записей passphrase у близких не нужно: достаточно того, что роль admin распределена между несколькими людьми.
Про recovery kit
Recovery kit — файл с приватным PGP-ключом, по сути сертификат пользователя. Нужен, чтобы:
- добавить ещё одно устройство (второй ноутбук, рабочий комп, телефон);
- переустановить браузерное расширение или сменить браузер;
- восстановиться после переустановки системы.
Без recovery kit + passphrase новое устройство к Passbolt не подключить. Если оба админа потеряют свои recovery kit'ы одновременно — придётся пересоздавать аккаунт через второго админа (см. выше), с потерей истории.
Хранить можно локально — на самом устройстве в защищённой папке или на внешнем носителе. Это не публичный секрет: с одним только kit без passphrase войти нельзя, поэтому требования к нему мягче. Главное — не потерять, не выложить в публичный git и помнить, в каком закутке файл лежит.
Что сделать сразу
- Проверить SMTP. В админке:
Administration → Email server → Send test email. Если письмо не пришло — проблема сEMAIL_TRANSPORT_*переменными в.env. Без работающего SMTP не получится приглашать новых пользователей: им уходит письмо с ссылкой-инвайтом, аналогичной той, которая печаталась в stdout у первого admin'а. - Завести второго админа. Тем же
register_userили через UI после первого входа. Это страховка на случай потери passphrase, см. выше. - Сменить email админа на реальный, если использовали временный.
Приглашаем остальных пользователей
Дальше всё через UI: Users → New user. Каждому уходит письмо с ссылкой-инвайтом, по которой он генерирует свой PGP-ключ и задаёт passphrase — ровно тот же процесс, что и у admin'а, только без CLI-шага. Группы и расшаривание паролей — там же, в Users / Groups, без необходимости лезть в сервер.
9. Безопасность сервера и бэкапы
Сервис с паролями всей семьи — это не место для «настроим потом». Ниже базовый минимум: firewall, бэкапы, обновления и пара мелочей по SSH.
Firewall: оставляем только нужные порты
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Что закрывается этим: 81 (админка NPM, она и так на 127.0.0.1), 40080/40443 (порты Passbolt, тоже только loopback), 3306 (MariaDB, наружу не пробрасывалась вовсе). Снаружи остаются только три порта: SSH для администрирования и 80/443 для HTTPS-трафика.
Проверяем:
sudo ufw status verbose
Бэкапы
Что нужно сохранять, чтобы из бэкапа можно было поднять Passbolt с нуля на другом сервере:
~/passbolt/.env— пароли БД и SMTP, без него compose не стартанёт~/passbolt/docker-compose.yml— сам конфиг (по-хорошему он и так в git, но дублировать не вредно)- Docker-волюм
database_volume— данные MariaDB, основная ценность - Docker-волюм
gpg_volume— серверные PGP-ключи, без них зашифрованные данные в БД не расшифровать - Docker-волюм
jwt_volume— ключи для JWT-токенов, без них клиенты придётся перерегистрировать ~/passbolt/npm-dataи~/passbolt/npm-letsencrypt— конфиг NPM и сертификаты Let's Encrypt
Простой ежедневный бэкап-скрипт. Скрипт исходит из того, что compose-проект называется passbolt (volume'ы вида passbolt_gpg_volume). Если использовали официальный docker-compose-ce.yaml без явного name: в compose, имена volume'ов могут отличаться — см. примечание в шаге 5. Проверить можно командой sudo docker volume ls.
#!/bin/bash
set -euo pipefail
BACKUP_DIR=/var/backups/passbolt
TIMESTAMP=$(date +%Y-%m-%d_%H-%M)
mkdir -p "$BACKUP_DIR"
cd ~/passbolt
# Дамп БД через работающий контейнер
docker compose exec -T db mariadb-dump \
-u passbolt -p"$(grep DB_PASSWORD .env | cut -d= -f2)" \
passbolt | gzip > "$BACKUP_DIR/db_$TIMESTAMP.sql.gz"
# Конфиги и npm-данные
tar -czf "$BACKUP_DIR/files_$TIMESTAMP.tar.gz" \
.env docker-compose.yml npm-data npm-letsencrypt
# Volume'ы Passbolt (gpg + jwt)
docker run --rm \
-v passbolt_gpg_volume:/gpg:ro \
-v passbolt_jwt_volume:/jwt:ro \
-v "$BACKUP_DIR":/backup \
alpine tar -czf "/backup/volumes_$TIMESTAMP.tar.gz" /gpg /jwt
# Ротация: удалить файлы старше 30 дней
find "$BACKUP_DIR" -type f -mtime +30 -delete
Сохранить как ~/passbolt/backup.sh, дать chmod +x, в root'овый крон (скрипт пишет в /var/backups/, куда обычному юзеру записать нельзя; внутри скрипта команды docker идут без sudo, потому что cron работает из-под root):
sudo crontab -e
# каждый день в 4:00
0 4 * * * /home/youruser/passbolt/backup.sh
Проверить вручную перед тем, как доверять крону:
sudo /home/youruser/passbolt/backup.sh
ls -lah /var/backups/passbolt/
Куда складывать сами бэкапы. Локальная копия на VPS — это половина решения; если умрёт диск или хостер, исчезнут и они. Бэкапы нужно регулярно отгружать наружу — в любое отдельное хранилище: второй VPS, домашний NAS через rsync, S3-совместимое хранилище (Selectel, Yandex Cloud, Backblaze), внешний диск через scp. Что критически важно: бэкапы шифровать перед отправкой наружу (gpg -c или age — самый простой путь). В архивах лежат .env с паролем БД и server-side PGP-ключи; в облаке без шифрования это не бэкап, а вторая копия проблемы.
Проверка восстановления. Раз в полгода — поднять бэкап на отдельной VM или локально в Docker и убедиться, что Passbolt запускается, БД читается, пользователи входят. Бэкап, который ни разу не восстанавливали — это не бэкап, а надежда.
Обновления
Passbolt и MariaDB обновляются через образы. У Passbolt тег latest-ce — это плохо для прода: мажорное обновление может прилететь без предупреждения и сломать миграции. Лучше пинить к конкретной версии и обновляться осознанно:
image: passbolt/passbolt:5.2.0-1-ce # пример, актуальную версию смотреть на passbolt.com/docs
Чек-лист апдейта:
- Сделать бэкап (см. выше).
- Прочитать release notes — особенно секцию breaking changes.
sudo docker compose pull && sudo docker compose up -d- Проверить, что вход работает и письма уходят.
Систему обновлять отдельно — unattended-upgrades для security-патчей и ручной apt upgrade раз в пару недель. На single-purpose VPS это малозатратно.
Минимум по SSH
Если ещё не сделано — три быстрые вещи:
# 1. Запретить логин по паролю (только ключи)
sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart ssh
# 2. Поставить fail2ban (банит IP после нескольких неудачных попыток)
sudo apt install fail2ban
# 3. (опционально) Сменить SSH-порт на нестандартный
# — снижает шум от ботов, но не защита; сначала открыть новый порт в ufw,
# потом менять в sshd_config, иначе можно лишиться доступа
Перед PasswordAuthentication no обязательно убедиться, что SSH-ключ работает: открыть второй терминал и зайти по ключу, не закрывая первый. Если второй сеанс не пускает — править на месте, не доводить до залоченного сервера.
Как пользоваться Passbolt — коротко
Подробного разбора UI в этой статье не будет — Passbolt активно развивается, и любые скриншоты протухают за пару релизов. Вместо этого — карта основных сценариев с отсылками к официальной документации.
Браузерное расширение
Расширение для Chrome, Firefox, Edge — основной способ работы с сервисом. Без него Passbolt в веб-интерфейсе не открывается: расширение держит локальный PGP-ключ и расшифровывает пароли на клиенте, сервер этих данных не видит. Ставится один раз на каждом устройстве, импортирует recovery kit + passphrase — после этого браузер сам подставляет пароли в формах входа.
Документация по браузерному расширению →
Мобильные приложения
iOS и Android есть, но это просмотр и копирование паролей, не автозаполнение системного уровня (в отличие от 1Password/Bitwarden). Для семьи в большинстве сценариев этого хватает: открыл, скопировал, вставил. На рабочем телефоне с десятками логинов это может ощущаться медленно.
Группы и расшаривание
Главная фича, ради которой всё это и затевалось. Базовая модель:
- Группы — например, «Семья», «Работа», «Подписки». Пользователь в группе автоматически получает доступ ко всем паролям группы.
- Пароли с индивидуальным шарингом — конкретный пароль выдаётся конкретным людям с правами read / update / owner.
- Аудит — на каждом пароле видно, кому и когда был выдан доступ, кто и когда менял. На странице пользователя — все пароли, к которым у него есть доступ. Уволили сотрудника / расстался с подрядчиком — видно ровно то, что нужно ротировать.
Импорт паролей из других мест
Passbolt умеет импортировать KDBX (KeePass), CSV (универсальный экспорт), форматы 1Password, LastPass, Bitwarden. Это правильный момент наконец-то перенести тот самый Google Docs с паролями и закрыть исходную дыру.
CLI и API
Для автоматизации (CI/CD, выдача паролей сервисам, ротация секретов) есть официальный CLI и REST API. В контексте этой статьи это уже за рамками, но факт того, что они есть — один из аргументов в пользу Passbolt против Vaultwarden, если планируется когда-нибудь дорасти до использования в pipeline'ах.
Готово
На этом цикл закрывается:
- Пароли больше не лежат в Google Docs.
- Доступ выдаётся явно, отзывается явно, видно кому что выдано.
- Семья / команда пользуется одним инструментом на всех устройствах.
- Сервер — свой, сертификат — настоящий, бэкапы — есть.