Встановлення
У командах нижче замініть:
school.example.ua— на ваш домен;<IP>— на IP-адресу сервера;1.1.0— на номер найновішої версії (список версій — на сторінці github.com/tabula-cms/tabula, розділ Releases).
Код і образи сайту беруться з публічного репозиторію проєкту tabula-cms/tabula — ця назва в
командах лишається як є.
Каталог сайту на сервері — /opt/tabula (так він називається за замовчуванням). Якщо хочете
інший, замінюйте його всюди однаково.
Крок 1. Підготувати сервер (один раз, від root)
Section titled “Крок 1. Підготувати сервер (один раз, від root)”Під’єднайтеся до сервера як root — паролем, який видав хостинг, або через веб-консоль у панелі хостингу:
ssh root@<IP>Завантажте й запустіть скрипт підготовки. У DEPLOY_PUBLIC_KEY вставте публічний ключ з
попереднього розділу (рядок ssh-ed25519 AAAA…), у лапках:
curl -fsSL https://raw.githubusercontent.com/tabula-cms/tabula/main/scripts/server-setup.sh -o server-setup.shAPP_DIR=/opt/tabula DEPLOY_PUBLIC_KEY="ssh-ed25519 AAAA..." bash server-setup.shСкрипт (scripts/server-setup.sh):
- оновлює систему і встановлює Docker (з офіційного репозиторію Docker);
- вмикає автоматичні оновлення безпеки системи й додає 2 ГБ swap (запас пам’яті на пікові моменти, наприклад оновлення сайту під час бекапу);
- обмежує розмір журналів Docker, щоб вони не заповнили диск;
- створює користувача
deploy— ним ви надалі працюватимете з сайтом; він може керувати контейнерами, але не має прав адміністратора системи; - дозволяє вхід для
deployлише вашим ключем; - вмикає брандмауер: відкриті тільки SSH, HTTP (80) і HTTPS (443);
- вимикає вхід по SSH паролем і прямий вхід root по SSH;
- створює каталоги
/opt/tabula/app(код),data(база й файли),backups(архіви),certbot(сертифікати);dataіbackupsодразу належать користувачу, від якого працює сайт у контейнері, — окремо дозволяти йому запис не потрібно; - ставить часовий пояс Europe/Kyiv.
Скрипт можна запустити повторно — те, що вже зроблено, він пропускає.
⚠️ Після цього кроку пароль root по SSH більше не працює. Запасний вхід — веб-консоль у панелі хостингу (там пароль root і далі чинний).
Крок 2. Завантажити код
Section titled “Крок 2. Завантажити код”З вашого комп’ютера під’єднайтеся як deploy:
ssh deploy@<IP>Отримайте файли сайту — вони потрібні для запуску (docker-compose.prod.yml, шаблон nginx,
скрипти). Беріть ту саму версію, що й образ, який запускатимете:
git clone https://github.com/tabula-cms/tabula.git /opt/tabula/appcd /opt/tabula/appgit checkout v1.1.0Усі подальші команди виконуються з каталогу /opt/tabula/app.
Крок 3. Файл налаштувань .env
Section titled “Крок 3. Файл налаштувань .env”Створіть .env із зразка і відкрийте в редакторі:
cp .env.example .envnano .env(У nano: зберегти — Ctrl+O, Enter; вийти — Ctrl+X.)
Кожна змінна пояснена в самому файлі. Ось що в кожній написати для сервера:
Інсталяція
Section titled “Інсталяція”| Змінна | Що вписати |
|---|---|
PORT |
Залиште 3000. nginx і перевірка стану звертаються до застосунку саме на цей порт |
LOG_LEVEL |
Залиште info. debug — лише на час пошуку проблеми |
SITE_SLUG |
Коротке латинське ім’я сайту: малі літери, цифри, дефіс, до 32 символів, наприклад school-12. З нього складаються назва куки входу в адмін-панель і назви архівів бекапу. Потім не змінюйте: нове ім’я розлогінить усіх, а старі архіви зникнуть зі сторінки «Бекапи» |
SITE_DOMAIN |
Домен без www і без https://: school.example.ua |
SITE_URL |
Адреса сайту зі схемою, без скісної риски в кінці: https://school.example.ua. З неї будуються карта сайту, RSS і посилання для соцмереж |
APP_DIR |
/opt/tabula |
APP_IMAGE |
Образ сайту з номером версії, малими літерами: ghcr.io/tabula-cms/tabula:1.1.0 |
UPDATE_REPO |
tabula-cms/tabula — звідки сайт раз на добу дізнається про нові версії |
UPDATE_CHECK |
1 — перевіряти нові версії, 0 — не перевіряти |
TRUST_PROXY |
1. Сайт стоїть за nginx; з 0 вхід в адмін-панель не працюватиме |
Дані й бекапи
Section titled “Дані й бекапи”| Змінна | Що вписати |
|---|---|
DATA_DIR, BACKUP_DIR |
Залиште порожніми: docker-compose.prod.yml задає їх сам (/opt/tabula/data і /opt/tabula/backups на сервері) |
BACKUP_S3_ENDPOINT, BACKUP_S3_REGION, BACKUP_S3_BUCKET, BACKUP_S3_KEY, BACKUP_S3_SECRET, BACKUP_S3_PREFIX |
Копія бекапів поза сервером. Можна лишити порожніми зараз і заповнити пізніше — див. Бекапи і відновлення |
Пошта форми зворотного зв’язку
Section titled “Пошта форми зворотного зв’язку”Заповніть один із двох блоків. Без жодного сайт не запуститься; якщо заповнено обидва, діє SMTP.
Gmail:
| Змінна | Що вписати |
|---|---|
EMAIL_USER |
Адреса Gmail, з якої надсилаються листи |
EMAIL_PASS |
Пароль застосунку (App Password) цього акаунта, не звичайний пароль |
Будь-який SMTP-сервер:
| Змінна | Що вписати |
|---|---|
SMTP_HOST |
Адреса SMTP-сервера від постачальника пошти |
SMTP_PORT |
Зазвичай 587; для 465 ще й SMTP_SECURE=1 |
SMTP_SECURE |
0 для порту 587, 1 для порту 465 |
SMTP_USER, SMTP_PASS |
Логін і пароль до SMTP-сервера |
MAIL_FROM |
Адреса відправника, наприклад no-reply@school.example.ua; порожня — SMTP_USER |
І для обох варіантів:
| Змінна | Що вписати |
|---|---|
CONTACT_TO |
Куди приходять листи з форми, наприклад скринька секретаря. Порожнє — на адресу відправника |
Безпека і перше налаштування
Section titled “Безпека і перше налаштування”| Змінна | Що вписати |
|---|---|
SESSION_SECRET |
Довгий випадковий рядок, мінімум 32 символи. Згенеруйте: openssl rand -hex 32. Без нього сайт не запуститься; зміна потім виведе всіх з адмін-панелі |
SETUP_CODE |
Одноразовий код для майстра першого налаштування. Найпростіше — задати свій: openssl rand -hex 6. Порожнє — сайт згенерує код сам і напише його в журнал запуску (див. крок 6) |
HEALTH_TOKEN |
Необов’язково: довгий випадковий рядок (openssl rand -hex 32). Без нього /health ззовні показує лише status і version; із заголовком Authorization: Bearer <токен> — ще й стан бекапів і диска (так перевіряють сайт деплой через GitHub Actions і монітор) |
Приклад заповненого .env (усі значення вигадані):
PORT=3000LOG_LEVEL=infoSITE_SLUG=school-12SITE_DOMAIN=school.example.uaSITE_URL=https://school.example.uaAPP_DIR=/opt/tabulaAPP_IMAGE=ghcr.io/tabula-cms/tabula:1.1.0UPDATE_REPO=tabula-cms/tabulaUPDATE_CHECK=1DATA_DIR=BACKUP_DIR=BACKUP_S3_ENDPOINT=BACKUP_S3_REGION=BACKUP_S3_BUCKET=BACKUP_S3_KEY=BACKUP_S3_SECRET=BACKUP_S3_PREFIX=TRUST_PROXY=1SMTP_HOST=SMTP_PORT=587SMTP_SECURE=0SMTP_USER=SMTP_PASS=MAIL_FROM=EMAIL_USER=school12.site@gmail.comEMAIL_PASS=abcd efgh ijkl mnopCONTACT_TO=secretary@school.example.uaSESSION_SECRET=<64 символи з openssl rand -hex 32>SETUP_CODE=9b2e4c7a10d3HEALTH_TOKEN=<64 символи з openssl rand -hex 32>Збережіть файл і закрийте доступ до нього іншим користувачам сервера — у ньому паролі:
chmod 600 .envКрок 4. Завантажити образ сайту
Section titled “Крок 4. Завантажити образ сайту”Сайт на сервері не збирається з коду, а завантажується готовим Docker-образом — тим, що вказано в
APP_IMAGE. Образ публічний, тож входити в реєстр не потрібно:
docker compose -f docker-compose.prod.yml pull appКрок 5. Запустити сайт і отримати сертифікат HTTPS
Section titled “Крок 5. Запустити сайт і отримати сертифікат HTTPS”Переконайтеся, що домен уже вказує на сервер (див. Домен і сервер). Потім:
docker compose -f docker-compose.prod.yml up -d appCERTBOT_EMAIL="admin@school.example.ua" bash scripts/init-letsencrypt.shdocker compose -f docker-compose.prod.yml up -dCERTBOT_EMAIL— ваша справжня адреса: на неї Let’s Encrypt надсилає нагадування, якщо сертифікат не продовжився.scripts/init-letsencrypt.shзапускається один раз: тимчасово піднімає nginx лише на HTTP, отримує сертифікат і повертає справжній конфіг з HTTPS. Сертифікат дляwww.він запитує, лише якщо дляwwwє DNS-запис.- Далі сертифікат продовжується сам: контейнер
certbotперевіряє його приблизно раз на 12 годин.
Перевірте, що все запущено:
docker compose -f docker-compose.prod.yml pscurl -s https://school.example.ua/healthУ ps мають бути app, nginx, certbot; app — зі станом healthy (з’являється за хвилину
після старту). /health відповідає JSON, у якому "status":"ok" і "version":"1.1.0".
Відкрийте https://school.example.ua у браузері — має відкритися порожній сайт.
Крок 6. Перше налаштування в браузері
Section titled “Крок 6. Перше налаштування в браузері”Поки на сайті немає жодного облікового запису, його налаштовують майстром за адресою
https://school.example.ua/admin/setup. Майстер відкривається одноразовим кодом доступу:
-
якщо ви задали
SETUP_CODEу.env— це він; -
якщо ні — сайт згенерував код сам. Знайдіть його в журналі:
Terminal window docker compose -f docker-compose.prod.yml logs app | grep admin/setupРядок виглядає так:
Сайт ще не налаштовано: відкрийте /admin/setup і введіть код xxxx-xxxx-xxxx.
Далі два варіанти:
- пройдіть майстер самі, створивши обліковий запис адміністратора закладу (п’ять кроків: адміністратор, заклад, структура сайту, кольори, готово);
- або передайте адресу й код тому, хто керуватиме сайтом (секретарю, директору), — майстер докладно описано в посібнику адміністратора.
Після останнього кроку майстер зникає назавжди (/admin/setup відповідає «не знайдено»), а
згенерований файл з кодом видаляється. SETUP_CODE у .env після цього ні на що не впливає — його
можна стерти.
П’ять неправильних кодів з однієї адреси закривають майстер на 15 хвилин.
Крок 7. Після встановлення
Section titled “Крок 7. Після встановлення”- Увійдіть в адмін-панель (
https://school.example.ua/admin) і перевірте на дашборді рядок про бекап. Перший бекап сайт робить сам одразу після запуску. - Підключіть копію бекапів поза сервером — Бекапи і відновлення. Без неї всі копії зникнуть разом із сервером.
- Надішліть тестовий лист через форму на сторінці «Зворотний зв’язок» і переконайтеся, що він прийшов.
- Збережіть у надійному місці: IP сервера, пароль root, приватний SSH-ключ, копію
.env. Без них перенести сайт чи повернути доступ буде важко.
Корисні команди
Section titled “Корисні команди”Усі — з каталогу /opt/tabula/app під користувачем deploy:
docker compose -f docker-compose.prod.yml ps # що запущеноdocker compose -f docker-compose.prod.yml logs -f app # журнал сайту (вихід — Ctrl+C)docker compose -f docker-compose.prod.yml restart app # перезапустити сайтcurl -s https://school.example.ua/health # чи сайт відповідає (status, version)Далі: Бекапи і відновлення →