BookStack на VPS в Docker: своя база знаний за вечер вместо Confluence
BookStack — это открытая база знаний для команды: документацию, регламенты и внутренние инструкции можно держать не в десяти разрозненных Google-документах и не в переписке, а в одном месте. Главное её отличие от «плоских» вики вроде MediaWiki — жёсткая иерархия: содержимое живёт не в общем списке страниц, а по уровням «полка → книга → глава → страница». Сотрудник, которому нужен регламент по отпускам, открывает книгу «HR», а не ищет по всей базе в надежде, что нужная страница вообще существует. Редактор — привычный WYSIWYG с возможностью переключиться на Markdown, поэтому обучение нетехнических сотрудников занимает минуты. За Confluence пришлось бы платить за каждого пользователя, а BookStack ставится на собственный сервер бесплатно, и все данные остаются у вас.
Ниже — установка на Ubuntu 24.04 вручную и вариант в Docker Compose, а также ошибки, на которые натыкаются почти все, и уход за базой знаний после запуска.
Что понадобится
BookStack — обычное Laravel-приложение на PHP, без Node.js на сервере: собранный фронтенд (CSS и JS) уже лежит в ветке release репозитория. Стек минимальный:
- nginx — приём HTTP/HTTPS и отдача статики;
- php8.3-fpm — выполнение приложения;
- mariadb-server — хранение книг, страниц, ролей и настроек;
- composer — сборка зависимостей PHP, без него не появится vendor/;
- git — получение кода из ветки release.
Подготовьте чистую Ubuntu 24.04 LTS с root-доступом, домен с A-записью на IP сервера и открытые порты 80/443. Для небольшой команды хватает 1 vCPU и 1 ГБ RAM — BookStack заметно легче Nextcloud, потому что почти не хранит файлов и превью. Если база знаний будет расти, ориентируйтесь на ориентиры из документации: до 15 человек — 1 vCPU / 2 ГБ / 20 ГБ диска, 15–50 человек — 2 vCPU / 4 ГБ / 40 ГБ, 50+ человек с большим числом вложений — 2–4 vCPU / 4–8 ГБ / от 60 ГБ. Вложения BookStack держит на диске, а не в базе, поэтому место расходуется под загруженные файлы.
Установка пошагово
Всё ставится из штатных репозиториев Ubuntu 24.04, без сторонних PPA:
apt update && apt -y full-upgrade
apt -y install nginx mariadb-server git unzip curl composer \
php8.3-fpm php8.3-mysql php8.3-xml php8.3-mbstring php8.3-curl \
php8.3-zip php8.3-gd php8.3-bcmath php8.3-intl
Пакет php8.3-common подтянется сам и уже несёт ctype, tokenizer, fileinfo, openssl и pdo. Отдельно проверьте набор расширений:
php -m | grep -icE 'mbstring|xml|curl|zip|gd|bcmath|intl|pdo_mysql|tokenizer|ctype|fileinfo'
Команда должна вернуть 10. Если не хватает pdo_mysql — забыли php8.3-mysql, и первая же миграция упадёт с ошибкой could not find driver. Расширение intl формально необязательно, но без него сортировка заголовков по алфавиту в русской локали идёт по порядку байт, а не букв — это заметно на глаз. Фаервол сразу закройте до минимума, а MariaDB наружу не открывайте — она должна слушать 127.0.0.1, а не 0.0.0.0:
ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp
ss -ltnp | grep 3306
Первый шаг к базе — создать хранилище и пользователя именно под BookStack:
CREATE DATABASE bookstack CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'bookstack'@'localhost' IDENTIFIED BY 'ДЛИННЫЙ_ПАРОЛЬ';
GRANT ALL PRIVILEGES ON bookstack.* TO 'bookstack'@'localhost';
utf8mb4 здесь не формальность: с обычным трёхбайтовым utf8 эмодзи и часть иероглифов в заголовках ломают вставку записи ошибкой Incorrect string value. Пользователя привязываем к localhost, а не к «%» — PHP-FPM и MariaDB на одной машине, ходить в базу по сети извне незачем.
Теперь код и зависимости. Клонируем именно ветку release — в ней лежит уже собранный фронтенд:
git clone https://github.com/BookStackApp/BookStack.git --branch release --single-branch bookstack
cd bookstack
composer install --no-dev --optimize-autoloader
Флаг --no-dev пропускает пакеты для тестов и отладки, а --optimize-autoloader строит классовую карту заранее, что на слабом VPS заметно по скорости первого отклика. Каталог vendor/ занимает около 150–200 МБ, установка — минуту-две. Типичная ошибка здесь — склонировать main вместо release: тогда страницы откроются голым HTML без стилей. Переустанавливать всё не нужно, достаточно git checkout release.
Остаётся конфиг, ключ и миграции:
cp .env.example .env
php artisan key:generate --no-interaction --force
php artisan migrate --no-interaction --force
В .env как минимум задайте APP_URL с точной схемой (wiki.example.com, без слэша в конце) и DB_PASSWORD. После правок прав и конфига включите фоновые задачи в cron — BookStack использует планировщик Laravel для отправки писем и уведомлений.
Docker Compose
Если не хочется возиться с PHP-FPM, nginx и composer вручную, весь стек поднимается одним файлом. Создайте каталоги данных и .env:
mkdir -p /opt/bookstack/{mysql-data,bookstack-data}
DB_ROOT_PASSWORD=замените_на_свой_root_пароль
DB_PASSWORD=замените_на_свой_пароль_приложения
APP_URL=https://knowledge.your-domain.example
Готовый docker-compose.yml (образ linuxserver упаковывает PHP-FPM, nginx и сам BookStack в один контейнер, поэтому файл короче официального варианта с двумя контейнерами):
services:
bookstack-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
retries: 10
bookstack:
image: lscr.io/linuxserver/bookstack:latest
container_name: bookstack
restart: unless-stopped
depends_on:
bookstack-mysql:
condition: service_healthy
environment:
APP_URL: ${APP_URL}
APP_KEY: ${APP_KEY:-}
DB_HOST: bookstack-mysql
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:
Ключ приложения руками заполнять не нужно — контейнер сгенерирует его при первом запуске. Порт смотрит только на 127.0.0.1: наружу отдавайте через реверс-прокси с HTTPS. Запуск и наблюдение за логами:
docker compose up -d
docker compose logs -f bookstack
Первый старт занимает 30–90 секунд: контейнер ждёт готовности MySQL (за это отвечает healthcheck), затем накатывает миграции. В логах не должно быть ошибок подключения к базе. После входа смените логин и пароль администратора (Профиль → Edit Profile) и в Settings → Registration отключите публичную самостоятельную регистрацию, если пользователей заводить вручную. Оставленный пароль по умолчанию на базе знаний, доступной снаружи, — обычная причина того, что посторонний просто заходит и читает внутренние регламенты.
Для этого проекта подойдёт небольшой VPS на 2 ГБ RAM — подборку таких тарифов смотрите в каталоге ServerScan; для вариантов с локацией в Европе есть, например, карточка провайдера Hetzner.
Частые ошибки и решения
Белый экран или голая 500 после установки. Почти всегда это права на директории, которые Laravel использует для кеша и логов:
sudo chown -R www-data:www-data storage bootstrap/cache public/uploads
sudo find storage bootstrap/cache -type d -exec chmod 775 {} \;
sudo find storage bootstrap/cache -type f -exec chmod 664 {} \;
Если экран всё ещё пуст — временно включите APP_DEBUG=true, посмотрите текст ошибки и обязательно верните APP_DEBUG=false: открытый debug-режим на проде показывает структуру путей и переменные окружения всем желающим. Второй источник 500-й — невыполненные миграции, их догоняет команда php artisan migrate --force.
Access denied при подключении к базе. BookStack требует MySQL 8+ или MariaDB 10.4+. Классическая ошибка SQLSTATE[HY000] [1045] Access denied означает расхождение данных в .env с реальными правами пользователя БД. В Docker есть отдельная ловушка: DB_HOST=localhost не сработает — внутри контейнера это сам контейнер, а не хост базы. Нужно имя сервиса из docker-compose.yml, в нашем файле это bookstack-mysql.
Ссылки и стили сломаны, картинки не грузятся. Если страница открывается «голой», ссылки ведут на http://localhost — виноват APP_URL. Он должен точно совпадать с тем, как заходят пользователи, включая схему. После изменения очистите кеш конфигурации, иначе Laravel продолжит использовать старое значение. За реверс-прокси проверьте, что передаются заголовки X-Forwarded-Proto и X-Forwarded-Host, — без них генерируются http-ссылки и браузер блокирует «смешанный контент».
Не загружаются изображения и файлы. Три причины по очереди: заниженные лимиты PHP (upload_max_filesize, post_max_size — в php.ini или пуле php-fpm, после правки нужен перезапуск php8.3-fpm); права на public/uploads и storage/uploads — оба пути должны принадлежать пользователю веб-сервера; лимит client_max_body_size на уровне nginx, который блокирует загрузку раньше, чем запрос дойдёт до PHP. Если включено S3-хранилище (STORAGE_TYPE=s3), проверяйте права доступа к bucket и корректность STORAGE_URL: файлы могут загружаться, но оставаться недоступными публично.
Не уходят письма. Смотрите .env: MAIL_USERNAME, MAIL_PASSWORD, MAIL_FROM_NAME и порт — 587 (STARTTLS) или 465 (SSL). Многие провайдеры режут исходящий 25-й порт по умолчанию для борьбы со спамом, поэтому Connection could not be established с хостом SMTP — это чаще блокировка провайдера, а не ошибка в настройках.
Бэкап и обновление
Для Docker-варианта весь стейт лежит в двух каталогах — mysql-data и bookstack-data (загруженные файлы, изображения, аватары). Останавливаем стек и архивируем оба:
docker compose down
tar czf bookstack-backup-$(date +%F).tgz mysql-data bookstack-data
Обновление: docker compose pull && docker compose up -d — контейнер сам накатит миграции. Для установки вручную обновляйтесь из репозитория и догоняйте схему:
git pull
composer install --no-dev --optimize-autoloader
php artisan migrate --force
Обязательно смотрите на ошибки после обновления версии: чаще всего всплывают те же проблемы прав и невыполненных миграций. Перед обновлением делайте дамп базы — откат версии без него превращается в ручную археологию.
Итог
BookStack даёт команде одну точку правды по документации без лицензионных платежей и без чужих серверов: WYSIWYG-редактор, понятная иерархия и права вплоть до отдельной страницы. Для старта достаточно VPS на 1–2 ГБ RAM, дальше объём зависит только от вложений. Следующие шаги после запуска: настроить реверс-прокси с HTTPS, включить фоновые задачи в cron, закрыть самостоятельную регистрацию, разделить сотрудников по ролям и поставить регулярный бэкап каталогов данных.