Встановлення Kestra на VPS: оркестрація завдань, Docker, PostgreSQL, SSL і розклади
Коротко
Kestra — self-hosted платформа для оркестрації завдань, ETL-пайплайнів, API-автоматизації та розкладів. У цьому посібнику ви розгорнете Kestra на Ubuntu VPS через Docker Compose, підключите PostgreSQL, закриєте інтерфейс HTTPS-проксі Caddy, створите перший workflow із cron-розкладом і налаштуєте резервне копіювання.
Для невеликого production-інстансу достатньо VPS із 2 vCPU, 4 ГБ RAM і 40–60 ГБ NVMe.
Kestra та PostgreSQL працюватимуть в окремих Docker-контейнерах.
Caddy автоматично випустить і продовжить TLS-сертифікат Let’s Encrypt.
Усі паролі зберігатимуться у файлі .env, а не в Docker Compose або workflow.
Перший workflow запускатиметься вручну та за cron-розкладом.
Бекапи PostgreSQL і конфігурації запускатимуться через cron і надсилатимуться до зовнішнього сховища.
Що ми налаштовуємо і навіщо
Kestra — це платформа оркестрації, у якій завдання описуються декларативними YAML-файлами. Вона підходить для запуску ETL-процесів, обробки файлів, синхронізації SaaS-сервісів, викликів API, регулярних звітів, обслуговування інфраструктури, запуску Python-скриптів, SQL-запитів і контейнерних job.
На відміну від простого cron, Kestra зберігає історію запусків, параметри, логи, статуси завдань, помилки та повторні спроби. Веб-інтерфейс дає змогу вручну запускати workflow, передавати вхідні дані, переглядати виконання покроково та повторно запускати невдалі процеси.
Після виконання інструкції на сервері працюватимуть такі компоненти:
Kestra Server із веб-інтерфейсом та API;
PostgreSQL 16 як надійна база даних для workflow, черг, execution history і метаданих;
Docker Compose для керування сервісами;
Caddy як reverse proxy з автоматичним HTTPS;
Firewall UFW, SSH-ключі та Fail2ban для базового захисту VPS;
регулярний backup PostgreSQL, конфігурації та persistent-даних Kestra;
приклад workflow із ручним запуском і cron-розкладом.
Що можна автоматизувати через Kestra
Сценарій
Приклад workflow
Частота запуску
ETL та аналітика
Забрати CSV із S3, очистити дані, завантажити в PostgreSQL
Конвертувати завантажені PDF, вилучити текст і зберегти результат
За подією
Звіти
Виконати SQL, зібрати звіт і надіслати його в Telegram або email
У будні о 09:00
Cloud-managed або self-hosted Kestra
Managed-версія знімає з команди завдання з оновлення, зберігання даних і масштабування, але додає регулярну оплату та залежність від зовнішньої платформи. Self-hosted Kestra на VPS потребує початкового налаштування, зате дає змогу контролювати місце зберігання даних, ліміти, мережеві правила, плагіни, вихідні IP-адреси та витрати.
Self-hosted варіант особливо зручний, якщо workflow працюють із внутрішніми базами, приватними API, закритими Git-репозиторіями або чутливими документами. Сервер можна розмістити в потрібній юрисдикції, підключити до VPN-мережі та обмежити доступ до панелі за IP або додатковою HTTP-аутентифікацією.
Не використовуйте вбудовану H2-базу Kestra для production-розгортання. Вона допустима для локальної розробки й тестів, але для VPS із реальними розкладами, журналами та кількома workflow використовуйте PostgreSQL.
Яка конфігурація VPS потрібна для цього завдання
Навантаження Kestra залежить не стільки від кількості YAML-файлів, скільки від характеру завдань, що виконуються. Якщо workflows лише викликають API та виконують SQL-запити, вимоги помірні. Якщо вони запускають Python-обробку файлів, Docker-контейнери, браузерну автоматизацію або трансформації великих таблиць, потрібні додаткові CPU, RAM і швидкий диск.
Профіль
CPU
RAM
Диск
Підходить для
Тестовий
1 vCPU
2 ГБ
25 ГБ NVMe
Вивчення інтерфейсу, 1–3 легких workflow
Мінімальний production
2 vCPU
4 ГБ
40–60 ГБ NVMe
До десятків API, SQL і cron-завдань на день
Робочий
4 vCPU
8 ГБ
100 ГБ NVMe
Команда, паралельні workflow, великі логи
Важкі обчислення
8 vCPU+
16–32 ГБ+
200 ГБ NVMe+
Python, Docker jobs, великі файли, ML та ETL
Практичний стартовий варіант — 2 vCPU, 4 ГБ RAM, 60 ГБ NVMe і канал від 100 Мбіт/с. Такий сервер зазвичай витримує сам Kestra, PostgreSQL, Caddy, базові системні служби та помірну кількість одночасно запущених завдань. Якщо ви збираєтеся запускати workflow із Docker-контейнерами, починайте з 4 vCPU і 8 ГБ RAM.
Для такого сценарію можна взяти VPS із зазначеними характеристиками, встановити Ubuntu Server 24.04 LTS і одразу налаштувати DNS-запис для майбутнього домену Kestra.
Коли потрібен dedicated-сервер
Виділений сервер потрібен не для самого інтерфейсу Kestra, а для важких workload. Переходьте на dedicated, якщо регулярно обробляєте десятки гігабайтів файлів, паралельно запускаєте багато контейнерів, потребуєте гарантованих CPU-ресурсів, високого IOPS або зберігаєте великий обсяг execution-логів локально.
Також dedicated має сенс, якщо Kestra запускає внутрішні CI-процеси, браузери Playwright, конвертацію відео, моделі машинного навчання або масштабні Spark-завдання. Для звичайної автоматизації API, SQL і бекапів VPS простіше, дешевше та легше масштабувати вертикально.
Як вибрати локацію
Локація впливає на затримку до бази даних, зовнішніх API та користувачів веб-інтерфейсу. Якщо Kestra підключається до бази в європейському дата-центрі, обирайте VPS поруч із нею. Якщо завдання працюють із локальними API або корпоративною мережею, важливішими є близькість до VPN-шлюзу та стабільна маршрутизація.
Для TLS-сертифіката та публічних webhook важливе інше: доменне ім’я має вказувати на публічний IP сервера, а порти 80 і 443 мають бути доступними з інтернету. До встановлення Caddy створіть A-запис, наприклад kestra.example.com, спрямований на IP VPS.
Підготовка сервера
Нижче передбачається чистий сервер з Ubuntu Server 24.04 LTS і доступом через SSH під користувачем root. Виконуйте початкові дії з локального термінала. Замініть SERVER_IP на зовнішню адресу свого VPS.
Створення адміністратора та налаштування SSH-ключа
Спочатку створіть окремого користувача. Не запускайте Docker Compose і не працюйте з Kestra під root без потреби. Ім’я користувача у прикладі — ops.
Додайте публічний SSH-ключ для нового користувача. Команду нижче запускають на локальному комп’ютері, де вже є ключ ~/.ssh/id_ed25519.pub.
ssh-copy-id ops@SERVER_IP
ssh ops@SERVER_IP
Переконайтеся, що вхід новим користувачем працює, і лише після цього вимикайте вхід root та автентифікацію за паролем. Відкрийте другий SSH-сеанс, щоб не втратити доступ у разі помилки конфігурації.
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
X11Forwarding no
AllowUsers ops
Перевірте синтаксис конфігурації та перезапустіть SSH-службу.
sudo sshd -t && sudo systemctl restart ssh
Оновлення системи та базові утиліти
Оновіть пакети до актуального стану. Для production-сервера корисно ввімкнути автоматичні security-оновлення, але оновлення Docker і Kestra краще виконувати окремо у контрольоване вікно.
Перевірте версію ядра та потребу в перезавантаженні. Якщо файл /var/run/reboot-required існує, перезапустіть VPS у відповідне вікно.
test -f /var/run/reboot-required && cat /var/run/reboot-required
sudo reboot
Firewall UFW і Fail2ban
На сервері мають бути відкриті лише SSH, HTTP і HTTPS. PostgreSQL не публікується назовні на порт 5432: Kestra звертається до нього через внутрішню Docker-мережу.
Якщо ви використовуєте нестандартний SSH-порт, спочатку дозвольте його в UFW і перевірте новий вхід, а вже потім закривайте старий порт. Не змінюйте SSH-порт як єдиний захід безпеки: ключі, вимкнення root-login і Fail2ban важливіші.
اِ
Встановлення ПЗ — покроково
Для розгортання використовуємо Docker Engine 27+ і Docker Compose Plugin v2. Kestra буде закріплена за конкретним тегом образу, а не за latest. Це захищає від випадкового оновлення під час перезапуску контейнерів.
Встановлення Docker Engine і Docker Compose
Додайте офіційний ключ і репозиторій Docker для Ubuntu. Команди виконуються від імені користувача ops через sudo.
Додайте користувача до групи Docker. Після виконання команди вийдіть із SSH-сеансу та підключіться знову: членство в групі застосовується лише для нового сеансу.
sudo usermod -aG docker ops
exit
Після повторного входу перевірте Docker. Контейнер hello-world має завершитися без помилок.
docker --version
docker compose version
docker run --rm hello-world
Група docker фактично надає користувачу права, порівнянні з правами root. Додавайте до неї лише довірених адміністраторів. Для невеликої інсталяції це зручніше, ніж виконувати кожну команду через sudo.
Встановлення Caddy
Caddy прийматиме трафік на портах 80 і 443, автоматично отримуватиме сертифікат Let’s Encrypt і пересилатиме запити до Kestra на localhost. Встановлюйте Caddy пакетом з офіційного репозиторію.
Перевірте, що Caddy запущено. Поки конфігурацію не змінено, він не проксуватиме Kestra.
sudo systemctl enable --now caddy
sudo systemctl status caddy --no-pager
Створення структури каталогів
Зберігайте конфігурацію проєкту в одному каталозі. У прикладі використовується /opt/kestra. Persistent-дані зберігатимуться в Docker named volumes, а файли конфігурації, експорт workflow і резервні копії — на хості.
Станом на 2026 рік перед production-встановленням обов’язково звіряйте актуальний стабільний тег у реєстрі образів Kestra та changelog проєкту. У прикладі використовується закріплений тег v0.24.0 як шаблон. Не замінюйте тег на latest; натомість оновлюйте його свідомо після створення резервної копії та перевірки release notes.
Конфігурація Kestra, PostgreSQL і SSL
Підготовка секретів
Згенеруйте окремі довгі паролі для PostgreSQL і базової HTTP-автентифікації Caddy. Файл .env не додавайте до Git і не надсилайте в месенджери. Права 600 забороняють читання файлу іншими користувачами сервера.
Створіть файл config/application.yml. У ньому Kestra використовує PostgreSQL як repository і queue backend. Локальне storage підходить для одного вузла Kestra. У разі переходу до кількох серверів storage потрібно перенести в S3-сумісне об’єктне сховище.
Basic authentication Kestra вимкнена, оскільки зовнішній доступ захищатиме Caddy. Це спрощує роботу з браузером і API, але означає, що Caddy має залишатися єдиною точкою входу. Порт Kestra не публікується назовні.
Docker Compose для Kestra і PostgreSQL
Створіть compose.yml. PostgreSQL не має секції ports, отже, доступний лише контейнерам у внутрішній Docker-мережі. Kestra публікується на 127.0.0.1:8080, тому Caddy на тому самому сервері може до неї звертатися, а інтернет — ні.
Параметр JAVA_OPTS обмежує heap Java до 1,5 ГБ. На VPS із 4 ГБ RAM це розумна відправна точка: решта пам’яті залишається PostgreSQL, ОС і файловому кешу. На сервері з 8 ГБ RAM можна збільшити -Xmx до 3–4 ГБ після спостереження за реальним споживанням пам’яті.
Запустіть сервіси у фоновому режимі та перевірте їхній статус. Перший запуск може тривати кілька хвилин: Kestra створює таблиці та застосовує міграції в PostgreSQL.
cd /opt/kestra
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 kestra
Перевірте локальний endpoint до налаштування проксі. Відповіддю може бути JSON або HTTP-перенаправлення залежно від версії Kestra, але кодом не має бути 502 або Connection refused.
Спочатку створіть bcrypt-хеш пароля для Caddy. Команда запросить пароль, який ви зберегли в .env. Не вставляйте пароль у командний рядок: він залишиться в shell history.
Створіть Caddyfile. Замість змінної в конфігурації вкажіть виведений хеш вручну на місці PASTE_BCRYPT_HASH_HERE. Це безпечніше, ніж залишати пароль у відкритому вигляді.
Замініть домен і хеш у файлі, створіть каталог журналів, потім перевірте синтаксис. Caddy отримує сертифікат автоматично після успішного завантаження конфігурації, якщо DNS уже вказує на сервер і порт 80 доступний ззовні.
Відкрийте https://kestra.example.com у браузері. Браузер попросить логін і пароль Caddy, після чого відкриється інтерфейс Kestra. Також перевірте TLS із консолі.
Відкрийте Kestra у браузері, створіть namespace, наприклад company.ops, потім перейдіть до розділу Flows і створіть flow. Для першої перевірки вставте наведений нижче YAML. Він записує повідомлення в логи та спрацьовує кожні 15 хвилин.
Збережіть workflow, натисніть Execute і відкрийте вкладку Executions. Має з’явитися статус SUCCESS. Потім дочекайтеся часу, кратного 15 хвилинам, або тимчасово замініть cron на для тесту щохвилини. Після перевірки поверніть звичайний розклад.
Не зберігайте токени API, ключі S3, паролі баз даних і webhook secrets безпосередньо в YAML. Використовуйте секрети Kestra, змінні середовища або зовнішній secret manager. Для початку можна створювати secrets через інтерфейс у namespace, а згодом підключити Vault, SOPS або хмарний secrets manager.
Резервні копії та обслуговування
Для відновлення Kestra потрібні не лише дані PostgreSQL. Необхідно зберегти конфігураційні файли, файл Compose, Caddyfile, файл секретів .env і persistent storage. PostgreSQL містить метадані, execution history, налаштування та дані черг; storage містить файли, створені завданнями й плагінами.
Наступний скрипт створює стиснений дамп PostgreSQL і архівує каталог конфігурації. Він зберігає останні 14 днів локально. Локальний backup не захищає від видалення VPS, тому потім його потрібно надсилати до S3-сумісного сховища або на окремий сервер.
Ім’я Docker volume зазвичай формується з імені каталогу та імені volume. У цьому випадку проєкт запускається з /opt/kestra, тому volume називається kestra_kestra_storage. Якщо команда повернула помилку про неіснуючий volume, подивіться точну назву через docker volume ls і виправте скрипт.
Надсилання backup до зовнішнього сховища
Для реального захисту зберігайте копії за межами основного VPS. Практичні варіанти: S3-сумісне об’єктне сховище, окремий backup VPS через SSH, Borg repository або Restic repository. Нижче наведено приклад із Restic і S3-сумісним backend. Змінні доступу помістіть в окремий файл із правами 600.
Ініціалізуйте репозиторій один раз, потім додайте завантаження даних у кінець backup-скрипта. Перед використанням перевірте параметри endpoint і bucket у вибраного S3-провайдера.
Для одного VPS оновлення — це коротке maintenance window, а не справжнє rolling deployment. Спочатку створіть backup, прочитайте release notes вибраної версії, оновіть тег образу в compose.yml, завантажте образ і перезапустіть лише контейнер Kestra.
cd /opt/kestra
./backup-kestra.sh
docker compose pull kestra
docker compose up -d --no-deps kestra
docker compose logs -f --tail=100 kestra
Після оновлення перевірте інтерфейс, виконання тестового workflow, розклад і міграції бази. Не видаляйте старий образ негайно: він може знадобитися для відкату, якщо нова версія несумісна з використовуваним плагіном. Перед оновленням major-версії PostgreSQL створіть окремий перевірений backup і дотримуйтеся процедури upgrade PostgreSQL, а не просто змінюйте тег контейнера.
Troubleshooting + FAQ
Чому Caddy не отримує TLS-сертифікат і в логах є помилка ACME?
Спочатку перевірте A-запис домену командою getent ahostsv4 kestra.example.com: вона має повертати IP VPS. Потім переконайтеся, що UFW дозволяє TCP-порти 80 і 443, а у провайдера немає додаткового cloud firewall. Перевірте, що інший вебсервер не зайняв порт 80: sudo ss -ltnp | grep ':80\|:443'. Після виправлення DNS і портів виконайте sudo systemctl reload caddy та перегляньте journalctl -u caddy.
Чому в браузері відображається 502 Bad Gateway?
Код 502 означає, що Caddy доступний, але не може підключитися до Kestra. Виконайте docker compose ps у каталозі /opt/kestra: контейнер Kestra має бути у стані running або healthy. Потім перевірте локально curl -I http://127.0.0.1:8080/. Якщо відповіді немає, перегляньте docker compose logs kestra і docker compose logs postgres. Частою причиною є те, що PostgreSQL ще не пройшов healthcheck або вказано неправильні змінні бази.
Kestra постійно перезапускається. Що перевірити?
Почніть із docker compose logs --tail=200 kestra. Помилки підключення до PostgreSQL зазвичай вказують на неправильний пароль, ім’я бази або пошкоджену конфігурацію JDBC. Помилки OutOfMemoryError означають, що VPS не вистачає RAM або параметр -Xmx має надто велике значення. Перевірте пам’ять через free -h і docker stats. На VPS із 2 ГБ RAM краще не запускати PostgreSQL і Kestra з важкими workflows одночасно.
Чому workflow за cron не запускається?
Перевірте, що flow збережено, увімкнено і він не містить помилок у YAML. У cron із п’яти полів вираз /15 * означає кожні 15 хвилин. Переконайтеся, що timezone вказано явно: без нього час може інтерпретуватися в UTC. Відкрийте розділ Executions і знайдіть помилки trigger. Також перегляньте логи: docker compose logs kestra | grep -i schedule. Для тестування тимчасово встановіть розклад щохвилини.
Яка конфігурація VPS підійде мінімально?
Для знайомства з Kestra можна використовувати 1 vCPU, 2 ГБ RAM і 25 ГБ NVMe, але це некомфортний production-варіант. Практичний мінімум для Kestra, PostgreSQL, Caddy і кількох невеликих workflow — 2 vCPU, 4 ГБ RAM і 40–60 ГБ NVMe. Якщо workflow запускають Python, Chromium, Docker-контейнери або обробляють файли, обирайте щонайменше 4 vCPU і 8 ГБ RAM.
Що обрати — VPS чи dedicated для цього завдання?
VPS достатньо для API-автоматизації, SQL-завдань, регулярних звітів, webhook і більшості невеликих ETL-процесів. Dedicated потрібен за постійного значного CPU-навантаження, десятків паралельних container jobs, великих обсягів локальних даних або суворої вимоги до виділених ресурсів. Зазвичай розумніше почати з VPS і стежити за docker stats, навантаженням CPU, IOPS і часом виконання workflow.
Чи можна відкрити PostgreSQL назовні для підключення з DBeaver?
Технічно можна, але для Kestra це зазвичай не потрібно й небезпечно. PostgreSQL має залишатися всередині Docker-мережі. Для адміністративного доступу використовуйте SSH-тунель: ssh -L 5432:127.0.0.1:5432 ops@SERVER_IP, але для цього тимчасово потрібно буде пробросити PostgreSQL лише на localhost. Безпечніший варіант — виконувати SQL-команди через docker compose exec postgres psql безпосередньо на сервері.
Чому backup не бачить Docker volume Kestra?
Спочатку виконайте docker volume ls і знайдіть volume, пов’язаний зі storage. Docker Compose формує ім’я з project name та імені volume, тому воно може відрізнятися від прикладу, якщо проєкт було запущено з іншого каталогу або з параметром -p. Виправте ім’я volume у backup-скрипті. Також перевірте права на каталог /opt/kestra/backups і переконайтеся, що cron запускається від користувача, який входить до групи docker.
Висновки та наступні кроки
Тепер на VPS працює Kestra з PostgreSQL, Docker Compose, HTTPS через Caddy, базовим захистом сервера, cron-розкладами та резервним копіюванням. Інстанс готовий до запуску production-workflow, якщо ви регулярно перевіряєте логи, вільне місце на диску та успішність backup.
Створіть окремі namespace для розробки та production, а секрети перенесіть у Kestra Secrets або зовнішній secret manager.
Налаштуйте сповіщення в Telegram, Slack або email для execution зі статусом FAILED.
За зростання навантаження винесіть storage у S3-сумісне сховище, PostgreSQL — на окремий сервер або managed-базу, а навантаження worker ізолюйте в окремих контейнерах.
Перед будь-яким оновленням Kestra створюйте перевірений backup і тестуйте критичні workflows вручну. Це важливіше за автоматичне оновлення образів і дає змогу швидко виконати відкат у разі несумісності плагінів або змін у конфігурації.
Чи був цей гайд корисним?
Ваш відгук допомагає нам покращувати гайди.
Share this post:
Надішліть гайд тому, кому він може стати в пригоді.