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, закрыть самостоятельную регистрацию, разделить сотрудников по ролям и поставить регулярный бэкап каталогов данных.