BookStack в Docker Compose: готовый файл
Документация компании обычно расползается по трём местам сразу: часть в Google Docs, часть в чатах, часть в голове у одного сотрудника, который вот-вот уйдёт в отпуск. Confluence решает проблему, но стоит денег за каждого пользователя и требует отдельной инфраструктуры; Notion — красивый, но данные лежат на чужих серверах, а поиск по большому объёму текста работает не всегда быстро. BookStack — практичная середина: понятная структура «книга → глава → страница», простой WYSIWYG-редактор, который не пугает нетехнических сотрудников, и всё это разворачивается одним docker-compose.yml на своём сервере. Ниже — рабочий файл и разбор нюансов, которые на голом конфиге не видны.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Почему BookStack, а не Wiki.js или Confluence
BookStack написан на PHP (Laravel) с MySQL/MariaDB в качестве хранилища — стек скучный и предсказуемый, что для базы знаний скорее плюс: меньше шансов, что через два года проект внезапно сменит архитектуру или бросит поддержку.
Ключевая идея BookStack — жёсткая иерархия контента, а не плоский список страниц, как в большинстве вики-движков:
- Полки (Shelves) — верхний уровень, группируют книги по темам (например, «Отдел разработки», «HR», «Инфраструктура»).
- Книги (Books) — соответствуют одному продукту, процессу или разделу знаний.
- Главы (Chapters) — опциональный промежуточный уровень внутри книги.
- Страницы (Pages) — сам контент, с WYSIWYG или markdown-редактором на выбор.
Такая структура снижает хаос, привычный для плоских вики: сотрудник, который ищет регламент по отпускам, идёт в книгу «HR», а не гуглит по всей базе в надежде, что нужная страница вообще существует.
Сравнение с ближайшими альтернативами:
| BookStack | Wiki.js | Confluence | |
|---|---|---|---|
| Лицензия | MIT, self-hosted | AGPL, self-hosted | проприетарная, SaaS/self-hosted |
| Хранилище | MySQL/MariaDB | PostgreSQL, MySQL, SQLite | своя закрытая БД |
| Структура контента | книга → глава → страница | плоский список + теги | пространство → страница |
| Редактор | WYSIWYG (TinyMCE) + markdown | markdown, WYSIWYG, AsciiDoc | WYSIWYG |
| Права доступа | по ролям, вплоть до отдельной страницы | по ролям | по пространствам |
| Стоимость | бесплатно | бесплатно | от $$ за пользователя |
Wiki.js гибче по редакторам и хранилищу, но его плоская модель с тегами хуже масштабируется, когда книг становится много и нужна навигация «сверху вниз». Confluence удобнее для больших организаций с готовыми интеграциями (Jira и т.д.), но каждый дополнительный пользователь — это статья расходов, которой на self-hosted BookStack просто нет.
Требования к серверу
BookStack — не тяжёлое приложение, но и не игрушка: PHP-FPM плюс MySQL съедают заметно больше, чем условный статический сайт.
| Размер команды | vCPU | RAM | Диск |
|---|---|---|---|
| до 15 человек | 1 | 2 ГБ | 20 ГБ |
| 15-50 человек | 2 | 4 ГБ | 40 ГБ |
| 50+ человек, много вложений | 2-4 | 4-8 ГБ | от 60 ГБ |
Оценка ориентировочная — реальное потребление сильно зависит от объёма загружаемых файлов и картинок на страницах (BookStack хранит вложения на диске, а не в базе).
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверГотовый docker-compose.yml
Структура каталогов на сервере:
/opt/bookstack/
├── mysql-data/ # данные MariaDB
├── bookstack-data/ # загруженные файлы, изображения, аватары
├── .env
└── docker-compose.yml
Создаём каталоги и файл переменных окружения:
mkdir -p /opt/bookstack/{mysql-data,bookstack-data}
cd /opt/bookstack
nano .env
Содержимое .env — пароли сгенерируйте сами, не оставляйте примеры из статьи:
DB_ROOT_PASSWORD=замените_на_свой_root_пароль
DB_PASSWORD=замените_на_свой_пароль_приложения
APP_KEY=
APP_URL=https://knowledge.your-domain.example
APP_KEY заполнять руками не нужно — контейнер сгенерирует его сам при первом запуске и допишет в переменные окружения контейнера (не в файл .env), если оставить поле пустым в docker-compose.yml через APP_KEY: без значения — так и оставляем.
Сам docker-compose.yml:
services:
mysql:
image: mariadb:11
container_name: bookstack-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: bookstack
MYSQL_USER: bookstack
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql-data:/var/lib/mysql
networks:
- bookstack-net
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 6
bookstack:
image: lscr.io/linuxserver/bookstack:latest
container_name: bookstack
restart: unless-stopped
depends_on:
mysql:
condition: service_healthy
environment:
PUID: "1000"
PGID: "1000"
TZ: "Europe/Moscow"
APP_URL: ${APP_URL}
DB_HOST: mysql
DB_PORT: "3306"
DB_DATABASE: bookstack
DB_USERNAME: bookstack
DB_PASSWORD: ${DB_PASSWORD}
volumes:
- ./bookstack-data:/config
ports:
- "127.0.0.1:6875:80"
networks:
- bookstack-net
networks:
bookstack-net:
driver: bridge
Образ lscr.io/linuxserver/bookstack выбран сознательно — сборка от LinuxServer.io упаковывает PHP-FPM, nginx и сам BookStack в одном контейнере, что упрощает файл по сравнению с «официальным» вариантом из документации проекта, где веб-сервер и приложение разнесены на два контейнера. Для небольшой базы знаний разница не критична, а обслуживать один контейнер приложения вместо двух проще.
Порт снова смотрит только на 127.0.0.1 — наружу отдаём через реверс-прокси с HTTPS, отдельный раздел ниже.
Первый запуск и вход администратором
Поднимаем стек:
docker compose up -d
docker compose logs -f bookstack
Первый старт занимает 30-90 секунд — контейнер ждёт готовности MySQL (за это отвечает healthcheck), затем накатывает миграции схемы. В логах должна появиться строка о старте PHP-FPM или nginx без ошибок подключения к базе.
Открываем http://<IP-сервера>:6875 (или домен, если прокси уже настроен). Данные для входа по умолчанию:
Email: admin@admin.com
Password: password
Первым делом — смените и почту, и пароль администратора: Профиль → Edit Profile. Оставленный дефолтный пароль на базе знаний, доступной снаружи, — обычная причина, по которой посторонний просто заходит и читает внутренние регламенты компании.
Дальше стоит сразу зайти в Settings → Registration и отключить публичную самостоятельную регистрацию, если пользователей планируется заводить вручную или через приглашения — по умолчанию форма регистрации в некоторых версиях включена.
Структура контента и права доступа
Создание иерархии в BookStack интуитивно: + Create New → Book, внутри книги — + New Page или + New Chapter для промежуточного уровня. Полки создаются отдельно и потом собирают книги через Edit Shelf → добавить книги.
Права доступа настраиваются на нескольких уровнях одновременно:
- Роли (
Settings → Roles) — набор глобальных разрешений: кто может создавать книги, кто редактировать чужие страницы, кто управлять пользователями. Есть готовые ролиAdmin,Editor,Viewer, можно создавать свои. - Permissions на конкретной сущности — у любой полки, книги, главы или страницы можно вручную переопределить, какие роли и какие конкретные пользователи имеют доступ (
... → Permissionsв меню сущности). Это удобно, когда, например, книга «Финансы» должна быть видна только определённому отделу, хотя остальная база знаний открыта всем.
Для входа через существующий каталог пользователей BookStack поддерживает LDAP и SAML2 из коробки — настройка через переменные окружения AUTH_METHOD=ldap и соответствующий блок LDAP_* параметров (сервер, base DN, атрибуты). Если в компании уже поднят LDAP-сервер, это избавляет от дублирования учёток между базой знаний и остальными системами.
Полезная функция для навигации по большой базе — тегирование страниц (Page → Edit → Tags) вместе с полнотекстовым поиском по индексу MySQL, без отдельного поискового движка — для баз в пределах нескольких тысяч страниц этого достаточно.
HTTPS и доступ извне через реверс-прокси
Отдавать вход с логином и паролем по HTTP нельзя — сессионные куки и пароли будут ходить открытым текстом. Проще всего закрыть это Caddy с автоматическим Let's Encrypt:
# /etc/caddy/Caddyfile
knowledge.your-domain.example {
reverse_proxy 127.0.0.1:6875
}
Если Caddy на сервере ещё не настроен, есть отдельный разбор установки Caddy с авто-SSL на VPS. Вариант с Traefik тоже работает, если стек уже собран вокруг него — логика проксирования описана в статье про Traefik как реверс-прокси для Docker.
После того как домен заработал по HTTPS, обязательно поправьте APP_URL в .env на реальный https:// адрес и пересоздайте контейнер:
docker compose up -d --force-recreate bookstack
BookStack использует APP_URL для генерации всех внутренних ссылок и ассетов — если оставить старый адрес, часть ссылок и загруженных изображений будет вести на неверный домен или на http://, что в браузере даёт предупреждение о смешанном контенте.
Резервное копирование и обновление
Данные BookStack живут в двух местах: MySQL (структура книг, текст страниц, права) и каталог bookstack-data (загруженные файлы, обложки книг, аватары). Бэкапить нужно оба, отдельно друг от друга бэкап бессмысленен.
Дамп базы вручную:
docker exec bookstack-mysql sh -c 'exec mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" bookstack' > /opt/bookstack/backups/bookstack-$(date +%F).sql
Восстановление:
docker exec -i bookstack-mysql sh -c 'exec mysql -u root -p"$MYSQL_ROOT_PASSWORD" bookstack' < /opt/bookstack/backups/bookstack-2026-08-15.sql
Каталог с файлами копируется обычным tar:
tar czf /opt/bookstack/backups/bookstack-data-$(date +%F).tar.gz -C /opt/bookstack bookstack-data
Если на сервере уже настроен регулярный бэкап других сервисов, логичнее включить оба каталога BookStack в общий пайплайн — например, через BorgBackup в Docker Compose, а не поддерживать отдельный cron-скрипт под один сервис.
Обновление — стандартный pull + up:
docker compose pull bookstack
docker compose up -d bookstack
Миграции схемы БД накатываются автоматически при старте новой версии контейнера. Перед мажорным обновлением (смена первой цифры версии BookStack) стоит свежий дамп базы сделать заранее и заглянуть в changelog проекта — как и у большинства зрелых Laravel-приложений, обратные миграции на такой версии BookStack штатно не поддерживает.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
BookStack можно связать с MySQL, вынесенной на отдельный сервер?
Да, укажите в DB_HOST адрес внешней базы вместо mysql. Если базу разворачиваете отдельно, пригодится статья про установку MySQL на VPS — там же про создание пользователя с правами только на нужную базу, что безопаснее, чем root-доступ из приложения.
Чем BookStack отличается от внутренней базы знаний с ИИ-поиском?
BookStack — классическая структурированная вики без встроенного семантического поиска: находит страницы по ключевым словам и тегам, но не отвечает на вопросы своими словами. Если нужен именно ИИ-ассистент поверх корпоративных документов, это отдельная задача — она разобрана в статье про внутреннюю базу знаний компании на VPS с ИИ.
Можно ли перенести контент из Confluence или другой вики в BookStack?
Прямого импорта из Confluence нет. Рабочий вариант — экспортировать страницы из Confluence в HTML или Markdown и завести в BookStack через API (POST /api/pages) скриптом, либо вставлять вручную через WYSIWYG-редактор постранично, если книг немного.
Что будет, если контейнер MySQL упадёт при активной записи страницы?
MariaDB с InnoDB (движок по умолчанию) устойчива к обрыву процесса — незавершённая транзакция откатится при следующем старте. Тем не менее регулярный бэкап остаётся обязательным: устойчивость к сбою процесса не защищает от испорченного диска или случайного DROP TABLE.
Сколько места реально займёт база знаний на 500 страниц?
Точную цифру дать нельзя — сильно зависит от количества и размера вложенных изображений, а не от текста самих страниц (текст в MySQL весит немного). Как ориентир: без активной работы с картинками и файлами база из нескольких сотен страниц обычно укладывается в единицы гигабайт, а основной рост диска идёт именно за счёт bookstack-data.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →