bolt Valebyte VPS від $4/міс — NVMe, запуск за 60 секунд.

Отримати VPS arrow_forward
eco Початковий Туторіал

Dokploy на VPS: власний Vercel/Heroku для деплою з GitHub

calendar_month Sep 15, 2026 schedule 26 хв. читання visibility 49 переглядів
Dokploy на VPS: свой Vercel/Heroku для деплоя из GitHub
info

Потрібен сервер для цього гайду? Ми пропонуємо виділені сервери та VPS у 50+ країнах з миттєвим налаштуванням.

Потрібен сервер для цього гайду?

Розгорніть VPS або виділений сервер за хвилини.

Dokploy на VPS: власний Vercel/Heroku для деплою з GitHub

TL;DR

Dokploy перетворює звичайний VPS на власну платформу деплою: ви підключаєте GitHub-репозиторій, задаєте домен і змінні оточення, а потім отримуєте автоматичне збирання, HTTPS і публікацію застосунку після кожного push у вибрану гілку.

  • Для невеликих проєктів достатньо VPS із 2 vCPU, 4 ГБ RAM і 50–80 ГБ NVMe-диска.
  • Dokploy встановлюється поверх Docker і Docker Swarm однією офіційною командою.
  • Для стабільної роботи потрібні DNS-записи для панелі та кожного опублікованого застосунку.
  • GitHub можна підключити через GitHub App, webhook або SSH-ключ для приватних репозиторіїв.
  • HTTPS зазвичай видається вбудованим Traefik через Let’s Encrypt; окремий Caddy поруч із Dokploy не потрібен і може конфліктувати за портами 80 і 443.
  • Резервувати потрібно не лише код, а й конфігурацію Dokploy, Docker volumes, бази даних і секрети.

Що ми налаштовуємо і навіщо

Dokploy — self-hosted PaaS-панель для деплою застосунків на власний сервер. За підходом вона нагадує Vercel, Heroku, Railway, Render або Coolify: розробник не підключається до сервера через SSH після кожної зміни, а робить push у GitHub. Платформа отримує код, збирає контейнер, запускає його, підключає домен і проксіює трафік через HTTPS.

У цьому посібнику буде налаштовано один VPS із Dokploy, доменним ім’ям для панелі, GitHub-інтеграцією та першим застосунком. Як приклад використовується типовий Node.js-застосунок, проте принцип однаковий для Python, Go, PHP, Ruby, Next.js, NestJS, Django, FastAPI, Laravel, статичних сайтів і Docker Compose-проєктів.

Що вийде в результаті

Після налаштування у вас буде сервер, де можна створювати проєкти та сервіси через вебінтерфейс Dokploy. Кожен сервіс зможе збиратися з GitHub-репозиторію, запускатися в Docker-контейнері, отримувати environment variables, домени, TLS-сертифікати та логи. Для окремих проєктів можна запускати PostgreSQL, Redis, MySQL, MongoDB або Docker Compose-стек поруч із застосунком.

  • Панель Dokploy буде доступна, наприклад, за адресою https://deploy.example.com.
  • Застосунок буде автоматично публікуватися після push у гілку main.
  • Секрети зберігатимуться в налаштуваннях сервісу, а не в репозиторії.
  • Трафік на портах 80 і 443 обслуговуватиметься вбудованим reverse proxy Dokploy.
  • Деплой можна буде відкотити через історію розгортань або повторний запуск попереднього коміту.
  • Дані та конфігурація регулярно надсилатимуться до зовнішнього резервного сховища.

Як влаштований деплой

Dokploy використовує Docker як середовище виконання та Docker Swarm як оркестратор навіть на одному сервері. Під час деплою платформа отримує вихідний код із GitHub, потім діє одним із двох способів: збирає образ за вашим Dockerfile або застосовує автоматичне збирання через Nixpacks. Після успішного збирання контейнер підключається до внутрішньої мережі, а Traefik спрямовує на нього запити за доменним ім’ям.

Для production-проєктів краще зберігати в репозиторії власний Dockerfile. Він робить збирання відтворюваним: той самий образ можна запустити локально, на staging-сервері та в production. Автоматичний builder зручний для прототипів, але за нестандартних системних бібліотек, монорепозиторію, фонових воркерів або складного збирання явний Dockerfile простіше супроводжувати.

Self-hosted чи managed-платформа

Критерій Managed PaaS Dokploy на VPS
Початкове налаштування Мінімальне Потрібно підготувати сервер, DNS і резервні копії
Контроль інфраструктури Обмежений тарифом і правилами платформи Повний контроль над Docker, мережею, логами та даними
Вартість Зростає з кількістю сервісів, трафіком і базами Фіксована вартість VPS до вичерпання ресурсів
Доступ до сервера Часто відсутній або обмежений Є root-доступ і можливість діагностики
Оновлення та безпека Переважно відповідальність провайдера Відповідальність власника сервера
Відповідний сценарій Швидкий запуск без адміністрування Кілька сервісів, контроль даних і передбачуваний бюджет

Self-hosted Dokploy особливо корисний solo-фaундеру, невеликій команді або агенції, яка обслуговує кілька застосунків. Один сервер може утримувати панель, API, frontend, worker, PostgreSQL, Redis і кілька staging-середовищ. Водночас важливо не плутати зручність PaaS із відсутністю експлуатації: сервер усе одно потрібно оновлювати, моніторити та резервувати.

Dokploy не замінює архітектуру застосунку. Якщо один VPS виходить із ладу, усі сервіси на ньому недоступні. Для першого production-етапу це часто прийнятно, але база даних і конфігурація мають мати зовнішні резервні копії з першого дня.

Яка VPS-конфігурація потрібна для цього завдання

Dokploy сам по собі не потребує багато ресурсів, але на сервері одночасно працюють Docker, Docker Swarm, reverse proxy, збирачі образів, тимчасові контейнери та ваші застосунки. Головна помилка під час вибору VPS — рахувати лише пам’ять самого застосунку та забувати про збирання Docker-образів, кеш, базу даних, логи й файлову систему.

Мінімальна та рекомендована конфігурація

Сценарій CPU RAM NVMe-диск Мережа Що вміститься
Тестовий стенд 1 vCPU 2 ГБ 30–40 ГБ 100 Мбіт/с Панель і один легкий застосунок без важкої БД
Мінімальний production 2 vCPU 4 ГБ 50–80 ГБ 100 Мбіт/с або 1 Гбіт/с Панель, 2–5 невеликих сервісів, PostgreSQL або Redis
Кілька SaaS-сервісів 4 vCPU 8 ГБ 160 ГБ NVMe 1 Гбіт/с Кілька застосунків, workers, staging і бази даних
Інтенсивне збирання 8 vCPU 16 ГБ 300+ ГБ NVMe 1 Гбіт/с Монорепозиторії, SSR, часті CI/CD-збирання, кілька середовищ

Для першого робочого сервера розумний старт — 2 vCPU, 4 ГБ RAM, 80 ГБ NVMe та публічна IPv4-адреса. Такої конфігурації достатньо для Dokploy, кількох Node.js або Python-сервісів, PostgreSQL із помірним навантаженням і Redis. Якщо база даних активно записує дані, диск важливіший за номінальну кількість ядер: обирайте NVMe, а не повільний HDD.

Як нейтральний варіант можна взяти VPS із зазначеними характеристиками, а потім збільшити CPU, RAM або диск після появи реального навантаження. Перед замовленням перевірте, що сервер має виділений публічний IPv4, доступ через SSH, можливість налаштувати reverse DNS за потреби та достатній ліміт вихідного трафіку.

Скільки місця реально потрібно

Docker-образи та build cache непомітно витрачають диск. Наприклад, застосунок вагою 300 МБ після кількох оновлень може залишити 2–5 ГБ старих шарів, проміжних образів і кешу. PostgreSQL, завантажені користувачами файли, логи та резервні копії збільшують потребу ще сильніше.

Не заповнюйте системний диск більш ніж на 75–80%. Коли Docker або PostgreSQL не можуть записати дані через повний диск, застосунок може почати повертати помилки, а відновлення займе більше часу, ніж звичайний перехід на більший тариф. Щонайменше раз на тиждень перевіряйте df -h і docker system df.

Коли потрібен dedicated, а не VPS

VPS підходить майже для всіх ранніх SaaS-проєктів, внутрішніх панелей, лендингів, API та невеликої клієнтської бази. Dedicated-сервер стає виправданим, коли продуктивність сусідніх віртуальних машин є неприйнятною, потрібен великий локальний NVMe-масив, стабільно високе навантаження CPU або база даних виконує велику кількість операцій запису.

  • Потрібен dedicated, якщо PostgreSQL постійно використовує понад 8–12 vCPU або потребує сотень гігабайт швидких даних.
  • Потрібен dedicated, якщо ви збираєте великі Docker-образи десятки разів на день і збирання заважають production-трафіку.
  • Потрібен dedicated, якщо на одному вузлі працюють десятки клієнтів із високим навантаженням.
  • Потрібен dedicated, якщо потрібні специфічні RAID-конфігурації, локальні резервні диски або гарантовані IOPS.
  • VPS залишається найкращим вибором, якщо важливіша простота масштабування й ви поки не знаєте реальний профіль навантаження.

Як вибрати локацію

Локація сервера впливає на затримку, вимоги до зберігання даних і ціну трафіку. Якщо аудиторія перебуває в Європі, сервер у європейському дата-центрі зазвичай дасть затримку 20–80 мс. Для користувачів з одного регіону обирайте найближчу локацію, але не розміщуйте єдину резервну копію в тому самому дата-центрі: пожежа, помилка акаунта або мережевий інцидент не повинні одночасно знищити production і копію.

Якщо застосунок обробляє персональні дані, враховуйте юридичні вимоги країни, договори з клієнтами та правила транскордонного передавання даних. Для технічної частини також важливі доступність IPv6, захист від DDoS, швидкість порту та можливість збільшення диска без перевстановлення ОС.

Підготовка сервера

Схема: Підготовка сервера
Схема: Підготовка сервера

Нижче передбачається свіжий VPS з Ubuntu Server 24.04 LTS x86_64. Станом на 2026 рік це зручна стабільна база з підтримуваними пакетами, актуальним ядром і тривалим терміном оновлень безпеки. Команди виконуються від root лише під час першого підключення; далі використовується окремий користувач deploy з правами sudo.

Підключіться та оновіть систему

Спочатку увійдіть на сервер за IP-адресою, яку надав провайдер. Якщо використовуєте пароль root, замініть його на SSH-ключ до відкриття панелі Dokploy.

ssh root@SERVER_IP

Команда створює SSH-сесію з новим сервером.

apt update && apt upgrade -y && apt autoremove -y

Команда встановлює всі доступні оновлення безпеки та видаляє непотрібні залежності.

timedatectl set-timezone Europe/Moscow

Команда задає часовий пояс; вкажіть свій регіон, щоб логи, cron-завдання та час деплою були зрозумілими.

Створіть користувача для адміністрування

Не працюйте постійно під root. Окремий користувач знижує ризик випадково видалити системні файли або виконати небезпечну команду з інструкції. Dokploy і Docker однаково запускатимуть контейнери з підвищеними привілеями на рівні хоста, тому доступ до sudo і Docker слід надавати лише адміністраторам.

adduser deploy
usermod -aG sudo deploy

Команди створюють користувача deploy і додають його до групи sudo.

mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
nano /home/deploy/.ssh/authorized_keys

Команди створюють каталог для SSH-ключів. Вставте у файл публічний ключ зі свого комп'ютера, зазвичай вміст файлу ~/.ssh/id_ed25519.pub.

chown -R deploy:deploy /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys

Команди призначають власника та безпечні права доступу до ключа.

Не закривайте поточну root-сесію, доки не перевірите новий вхід в окремому вікні термінала.

ssh deploy@SERVER_IP

Команда перевіряє, що вхід новим користувачем за ключем справді працює.

Вимкніть вхід за паролем і root SSH

Після успішної перевірки змініть налаштування SSH. Не виконуйте цей крок до додавання робочого ключа, інакше можна втратити доступ до сервера та доведеться використовувати VNC або rescue mode у провайдера.

sudo nano /etc/ssh/sshd_config.d/99-hardening.conf

Команда відкриває окремий конфігураційний файл SSH без зміни стандартного файлу пакета.

PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3

Ці параметри забороняють root-вхід і автентифікацію паролем, залишаючи лише SSH-ключі.

sudo sshd -t && sudo systemctl restart ssh

Команда спочатку перевіряє синтаксис конфігурації, потім перезапускає SSH лише за відсутності помилок.

Встановіть базові утиліти та захист від підбору паролів

sudo apt install -y ca-certificates curl gnupg git jq unzip vim htop \
  ufw fail2ban dnsutils rsync cron

Команда встановлює утиліти для завантаження пакетів, роботи з Git, DNS-перевірок, бекапів, моніторингу та firewall.

sudo systemctl enable --now fail2ban

Команда вмикає Fail2ban, який відстежує підозрілі спроби входу та тимчасово блокує IP-адреси.

Налаштуйте firewall до встановлення Dokploy

Dokploy має приймати вебтрафік на портах 80 і 443. Порт 22 потрібен для SSH. Спочатку панель зазвичай доступна на порту 3000, тому на час першого входу можна відкрити його лише зі своєї публічної IP-адреси. Якщо IP змінюється, тимчасово відкрийте 3000 для всіх, створіть акаунт і потім закрийте порт після налаштування домену та HTTPS.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from YOUR_PUBLIC_IP to any port 3000 proto tcp
sudo ufw enable

Команди забороняють увесь вхідний трафік за замовчуванням і відкривають лише SSH, HTTP, HTTPS та доступ до панелі з вашої IP-адреси.

sudo ufw status numbered

Команда виводить активні правила та дає змогу переконатися, що firewall не заблокував потрібні порти.

Для одного вузла Docker Swarm зазвичай не потрібно відкривати назовні порти міжвузлової взаємодії. Якщо пізніше додасте worker-ноди, між довіреними вузлами знадобляться TCP 2377, TCP/UDP 7946 і UDP 4789. Не відкривайте їх для всього інтернету: обмежте правила IP-адресами кластера або приватною мережею.

Підготуйте DNS до встановлення

Створіть DNS-запис типу A для панелі, наприклад deploy.example.com, що вказує на IPv4 сервера. Для застосунків можна створювати окремі записи A, наприклад api.example.com і app.example.com. Якщо DNS-провайдер підтримує wildcard, зручно створити запис .apps.example.com, але для першого запуску це необов'язково.

dig +short deploy.example.com A

Команда перевіряє, що доменне ім'я вже повертає публічну IP-адресу вашого VPS.

Не вмикайте проксування CDN до першого випуску сертифіката, якщо не розумієте його режими TLS. Особливо часто HTTPS ламається в режимі, де CDN підключається до origin через HTTP. Спочатку отримайте робочий сертифікат безпосередньо через Dokploy, потім за потреби вмикайте зовнішній proxy у режимі повного шифрування.

Встановлення ПЗ — покроково

Схема: Встановлення ПЗ — покроково
Схема: Встановлення ПЗ — покроково

Офіційний інсталятор Dokploy розгортає необхідні компоненти Docker, ініціалізує Docker Swarm і запускає сервіси панелі. На практиці Dokploy швидко розвивається, тому перед production-встановленням корисно прочитати вивід скрипта та зафіксувати дату встановлення в журналі змін. Не запускайте неперевірені curl-команди від root на сервері з уже запущеними критично важливими сервісами.

Перевірте ресурси та відсутність конфліктів

free -h
df -h /
nproc
sudo ss -ltnp | grep -E ':(80|443|3000)\s' || true

Команди показують обсяг пам'яті, вільне місце, кількість CPU та процеси, які вже зайняли порти 80, 443 або 3000.

Якщо на сервері вже працює Nginx, Apache, Caddy, Traefik або інший Docker PaaS, не встановлюйте Dokploy поверх нього без плану міграції. Вбудований ingress Dokploy повинен мати можливість слухати 80 і 443. Конфлікт портів — одна з найчастіших причин недоступності панелі та застосунків.

Встановіть Dokploy офіційним скриптом

curl -sSL https://dokploy.com/install.sh -o /tmp/dokploy-install.sh
less /tmp/dokploy-install.sh

Команди завантажують офіційний install script у тимчасовий файл і дають змогу переглянути його перед виконанням.

sudo sh /tmp/dokploy-install.sh

Команда запускає офіційний інсталятор Dokploy, який встановлює Docker-компоненти та розгортає платформу.

На свіжому Ubuntu інсталятор зазвичай завершує розгортання за кілька хвилин. Не перезавантажуйте VPS під час встановлення та не переривайте процес. Якщо система повідомляє про конфлікт пакетів Docker, спочатку видаліть старі тестові встановлення Docker, Docker Compose або конфліктний reverse proxy, попередньо зберігши потрібні дані.

Перевірте Docker і Docker Swarm

sudo docker version
sudo docker info --format '{{.ServerVersion}}'
sudo docker node ls

Команди підтверджують роботу Docker Engine, виводять версію daemon і перевіряють, що поточний сервер є активною manager-нодою Swarm.

Станом на 2026 рік орієнтуйтеся на актуальний підтримуваний Docker Engine з офіційного каналу встановлення та актуальний stable-реліз Dokploy. Не використовуйте застарілі інструкції, які пропонують Docker Engine 20.x або ранні compose-файли без перевірки: вони можуть конфліктувати із сучасними пакетами Ubuntu та вимогами Dokploy.

sudo docker service ls
sudo docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'

Команди показують сервіси Docker Swarm і запущені контейнери Dokploy.

Відкрийте панель уперше

Після встановлення відкрийте в браузері http://SERVER_IP:3000 або http://deploy.example.com:3000, якщо DNS вже оновився. Під час першого входу створіть адміністратора з унікальним довгим паролем. Для пароля використовуйте менеджер паролів, а не секрет із репозиторію чи чату.

Якщо порт 3000 відкритий лише для вашої IP-адреси через UFW, а браузер не підключається, спочатку перевірте вашу поточну публічну IP-адресу. Корпоративні VPN, мобільний інтернет і домашні провайдери можуть змінювати її протягом дня.

curl -I http://127.0.0.1:3000

Команда перевіряє доступність панелі локально на сервері; відповідь 200, 301, 302 або 401 зазвичай означає, що сервіс відповідає.

Зробіть перший технічний знімок стану

sudo mkdir -p /root/server-inventory
sudo docker service ls > /root/server-inventory/docker-services-initial.txt
sudo docker volume ls > /root/server-inventory/docker-volumes-initial.txt
sudo docker network ls > /root/server-inventory/docker-networks-initial.txt

Команди зберігають початковий список сервісів, volumes і мереж Docker, що допомагає під час діагностики та налаштування резервного копіювання.

Додайте користувача до групи Docker лише за потреби

Для більшості операцій Dokploy доступ до Docker зі звичайної консолі не потрібен: використовуйте sudo docker. Якщо ви все ж додаєте користувача deploy до групи docker, пам'ятайте, що це практично еквівалентно root-доступу: через Docker можна примонтувати файлову систему хоста або запустити привілейований контейнер.

sudo usermod -aG docker deploy

Команда надає користувачу deploy доступ до Docker без sudo; вийдіть із SSH і підключіться знову, щоб група застосувалася.

Перевірте автозапуск після перезавантаження

sudo reboot

Команда перезавантажує сервер і перевіряє, що Docker, Swarm і сервіси Dokploy коректно запускаються після рестарту.

Після повторного входу зачекайте одну-дві хвилини та виконайте перевірку.

sudo systemctl is-active docker
sudo docker service ls
curl -I http://127.0.0.1:3000

Команди підтверджують, що Docker активний, сервіси Swarm запущені, а панель відповідає локально.

Конфігурація Dokploy, GitHub і HTTPS

Після базового встановлення не поспішайте деплоїти production-код. Спочатку задайте адресу панелі, перевірте DNS, налаштуйте HTTPS і вирішіть, яким способом Dokploy читатиме репозиторії GitHub. Для публічного репозиторію достатньо HTTPS clone URL, але для приватного потрібен GitHub App, персональний токен з мінімальними правами або deploy key.

Налаштуйте домен панелі та HTTPS

В інтерфейсі Dokploy відкрийте загальні налаштування панелі та вкажіть домен, наприклад deploy.example.com. Переконайтеся, що A-запис уже вказує на IP VPS, а порти 80 і 443 доступні ззовні. Після цього увімкніть автоматичний TLS через вбудований Traefik і Let’s Encrypt.

Dokploy використовує вбудований Traefik для reverse proxy та сертифікатів. Тому не встановлюйте Caddy, Nginx або certbot у standalone-режимі на той самий сервер без явної потреби: усі ці інструменти претендують на 80 і 443. Для Dokploy правильний шлях — увімкнути вбудований TLS у налаштуваннях домену сервісу; Traefik виконає HTTP-01 challenge та автоматично продовжуватиме сертифікат.

Якщо у вас корпоративний DNS, закритий порт 80 або складна схема CDN, використовуйте DNS challenge лише після розуміння інтеграції DNS API. У звичайній конфігурації простіше відкрити 80/443 і дозволити Let’s Encrypt перевірити домен напряму. Перевірити публічний HTTPS можна після випуску сертифіката.

curl -I https://deploy.example.com
openssl s_client -connect deploy.example.com:443 -servername deploy.example.com < /dev/null 2>/dev/null | \
  openssl x509 -noout -issuer -dates -subject

Команди перевіряють HTTP-відповідь панелі та виводять видавця, строк дії та ім’я TLS-сертифіката.

Підключіть GitHub безпечним способом

Для команди найзручніший GitHub App: він надає Dokploy доступ лише до вибраних репозиторіїв і дозволяє отримувати події push. Створіть GitHub App у налаштуваннях організації або особистого акаунта, вкажіть URL callback і webhook URL, які показує інтерфейс Dokploy, та надайте мінімально необхідні права на читання вмісту репозиторію і metadata.

Якщо GitHub App поки не потрібен, використовуйте deploy key для одного приватного репозиторію. Це SSH-ключ без прав на весь акаунт, який можна відкликати окремо. Не використовуйте особистий SSH-ключ адміністратора сервера як ключ для GitHub.

Згенеруйте окремий ключ на сервері або в ізольованому адміністративному середовищі:

sudo -u deploy ssh-keygen -t ed25519 -C "dokploy-github-readonly" \
  -f /home/deploy/.ssh/dokploy_github_ed25519 -N ""

Команда створює окрему пару Ed25519-ключів без passphrase для read-only deploy key.

sudo cat /home/deploy/.ssh/dokploy_github_ed25519.pub

Команда виводить публічну частину ключа, яку потрібно додати в GitHub у розділі Deploy keys конкретного репозиторію.

У GitHub відкрийте Repository Settings → Deploy keys → Add deploy key, вставте публічний ключ і не вмикайте Allow write access, якщо застосунку не потрібно записувати в репозиторій. У Dokploy додайте SSH private key через інтерфейс проєкту або використовуйте GitHub App. Не копіюйте приватний ключ у Dockerfile, вихідний код або змінні, які бачать користувачі застосунку.

Підготуйте застосунок до контейнерного деплою

Нижче наведено мінімальний приклад Node.js-сервісу. Структура репозиторію:

my-service/
├── Dockerfile
├── .dockerignore
├── package.json
├── package-lock.json
└── src/
    └── server.js

Файл Dockerfile має явно оголошувати робочу директорію, production-залежності, порт і healthcheck. Не поміщайте в образ файл .env, SSH-ключі, каталоги node_modules і локальні артефакти збірки.

FROM node:22-alpine

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci --omit=dev

COPY src ./src

ENV NODE_ENV=production
ENV PORT=3000

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
  CMD node -e "fetch('http://127.0.0.1:3000/health').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"

CMD ["node", "src/server.js"]

Цей Dockerfile збирає production-образ на базі Node.js 22 LTS, відкриває порт 3000 і перевіряє endpoint /health.

node_modules
.git
.env
.env.
npm-debug.log
coverage
dist
Dockerfile
docker-compose.yml

Це приклад вмісту .dockerignore; він виключає зайві та чутливі файли з Docker build context.

import http from "node:http";

const port = Number(process.env.PORT || 3000);
const appName = process.env.APP_NAME || "my-service";

const server = http.createServer((req, res) => {
  if (req.url === "/health") {
    res.writeHead(200, { "Content-Type": "application/json" });
    return res.end(JSON.stringify({ status: "ok" }));
  }

  res.writeHead(200, { "Content-Type": "application/json" });
  res.end(JSON.stringify({ service: appName, environment: process.env.NODE_ENV }));
});

server.listen(port, "0.0.0.0", () => {
  console.log(${appName} listens on ${port});
});

Це мінімальний сервер з endpoint /health, який можна використовувати для перевірки доступності контейнера.

Створіть сервіс в інтерфейсі Dokploy

  1. Створіть новий Project, наприклад production або my-saas.
  2. Додайте Application всередині проєкту.
  3. Виберіть джерело GitHub і вкажіть репозиторій.
  4. Вкажіть гілку main або окрему гілку production.
  5. Виберіть build type Dockerfile, якщо Dockerfile розташований у корені репозиторію.
  6. Вкажіть внутрішній порт застосунку 3000.
  7. Додайте домен, наприклад api.example.com.
  8. Увімкніть HTTPS і автоматичне отримання сертифіката.
  9. Збережіть налаштування та натисніть Deploy.

У Dokploy внутрішній порт — це порт, який слухає застосунок усередині контейнера. Його не потрібно відкривати в UFW: зовнішній трафік має йти через Traefik на 80/443. Якщо ви відкриваєте порт контейнера безпосередньо назовні, ви обходите TLS, маршрутизацію та частину захисних механізмів платформи.

Передавайте секрети через environment variables

У налаштуваннях застосунку знайдіть блок Environment Variables і додайте змінні по одній. У production не зберігайте реальні ключі у файлі .env всередині GitHub-репозиторію. Для локальної розробки допустимий файл .env.example без секретних значень.

NODE_ENV=production
APP_NAME=my-production-api
DATABASE_URL=postgresql://app_user:CHANGE_ME@postgres:5432/app_db
REDIS_URL=redis://redis:6379
JWT_SECRET=replace-with-a-random-64-character-secret
SENTRY_DSN=https://[email protected]/1

Це приклад змінних оточення для production-сервісу. Значення DATABASE_URL, JWT_SECRET та API-ключі мають бути унікальними й не повинні потрапляти в Git.

openssl rand -base64 48

Команда генерує випадковий рядок, придатний для секрету сесій, JWT або внутрішнього ключа застосунку.

Після зміни environment variables зазвичай потрібен Redeploy, оскільки контейнер отримує змінні під час запуску. Для баз даних створюйте окремого користувача для кожного застосунку, а не використовуйте суперкористувача PostgreSQL. Це зменшує шкоду у разі витоку одного connection string.

Налаштуйте автодеплой із GitHub

Автодеплой запускається через webhook після push. У Dokploy увімкніть автоматичний deployment для потрібної гілки. При використанні GitHub App webhook зазвичай створюється через інтеграцію. За ручного налаштування додайте webhook у GitHub у розділі Settings → Webhooks, вкажіть URL, який показує Dokploy, виберіть подію push і задайте webhook secret.

Webhook secret має збігатися в GitHub і Dokploy. Він захищає endpoint від довільних запитів, які могли б ініціювати деплой. Не використовуйте один і той самий секрет для всіх репозиторіїв.

Для тесту зробіть нешкідливий коміт:

git checkout main
git pull --ff-only
git commit --allow-empty -m "chore: test Dokploy deployment"
git push origin main

Команди створюють порожній коміт і надсилають його до гілки, щоб перевірити webhook та автоматичну збірку без зміни вихідного коду.

Відкрийте в Dokploy історію deployments. Успішний запуск має пройти стадії clone, build, deploy і healthcheck. Якщо збірка успішна, але домен повертає 502, майже завжди проблема в неправильному внутрішньому порті, застосунку, що слухає лише 127.0.0.1, або неготовій залежності на кшталт PostgreSQL.

Перевірте застосунок ззовні та з контейнера

curl -i https://api.example.com/health

Команда перевіряє, що публічний домен застосунку відповідає через HTTPS і повертає статус 200.

sudo docker service ls
sudo docker service ps --no-trunc SERVICE_NAME
sudo docker service logs --tail 100 SERVICE_NAME

Команди показують стан сервісу, детальну причину невдалого запуску завдання та останні 100 рядків логів.

Ім’я SERVICE_NAME візьміть із виводу docker service ls. У Docker Swarm фактичне ім’я може містити префікс проєкту. Не видаляйте сервіси командою docker service rm, якщо ними керує Dokploy: панель втратить очікуваний стан. Для керованого застосунку використовуйте Redeploy, Stop, Restart або Delete через інтерфейс.

Резервні копії та обслуговування

GitHub зберігає код, але не зберігає дані застосунку, Docker volumes, завантажені користувачами файли, конфігурацію Dokploy і секрети. Тому репозиторій не можна вважати резервною копією production. Мінімальна стратегія — щоденний автоматичний бекап до зовнішнього S3-сумісного сховища або окремого VPS і періодична перевірка відновлення.

Що потрібно бекапити

Дані Чому потрібні Спосіб копіювання
Конфігурація Dokploy Проєкти, налаштування, домени, інтеграції та метадані Архів каталогів конфігурації після перевірки їхнього розташування
PostgreSQL/MySQL Основні дані застосунків Логічний dump через pg_dump або mysqldump
Docker volumes Uploads, persistent data, Redis persistence і дані сервісів Архівування після зупинки або snapshot на рівні диска
Environment variables і секрети Без них неможливо швидко відновити сервіс Зашифрований password manager або захищений offline-документ
Системні налаштування SSH, UFW, cron, DNS-нотатки, конфігурація моніторингу Архів /etc та інфраструктурний репозиторій без секретів

Перед написанням скрипта знайдіть реальні Docker volumes і контейнери на вашому сервері. Назви залежать від версії Dokploy, імен проєктів і способу створення бази. Не припускайте, що volume обов’язково називається postgres_data.

sudo docker volume ls
sudo docker ps -a --format 'table {{.Names}}\t{{.Image}}\t{{.Mounts}}'
sudo find /etc -maxdepth 2 -iname 'dokploy' -print

Команди показують volumes, монтування контейнерів і можливі каталоги конфігурації Dokploy.

Встановіть Restic для зовнішніх резервних копій

Restic шифрує архіви на боці сервера перед відправленням до віддаленого сховища. Підійдуть S3-сумісний bucket, Backblaze B2 через сумісний API, окреме сховище або другий VPS із SFTP. Не зберігайте єдину копію на тому самому диску, де працюють Docker і база даних.

sudo apt install -y restic

Команда встановлює Restic із репозиторію Ubuntu.

sudo install -m 700 -d /root/.config/restic
sudo nano /root/.config/restic/dokploy-backup.env

Команди створюють захищений каталог і відкривають файл із параметрами доступу до зовнішнього S3-сховища.

export RESTIC_REPOSITORY="s3:https://s3.example-storage.invalid/dokploy-prod"
export RESTIC_PASSWORD="CHANGE_TO_A_LONG_UNIQUE_RESTIC_PASSWORD"
export AWS_ACCESS_KEY_ID="S3_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="S3_SECRET_KEY"

Це приклад файлу /root/.config/restic/dokploy-backup.env; замініть значення на реальні та обмежте права доступу.

sudo chmod 600 /root/.config/restic/dokploy-backup.env
sudo bash -c 'source /root/.config/restic/dokploy-backup.env && restic snapshots || restic init'

Команди закривають файл від інших користувачів і або показують наявні snapshots, або ініціалізують новий зашифрований репозиторій.

Створіть скрипт щоденного бекапу

Нижче скрипт створює логічний дамп PostgreSQL із контейнера, архівує системні налаштування та відправляє їх до Restic. Замініть POSTGRES_CONTAINER, POSTGRES_USER і POSTGRES_DB на реальні значення. Для бази, створеної засобами Dokploy, їх можна переглянути в налаштуваннях сервісу та через docker ps.

sudo nano /usr/local/sbin/backup-dokploy.sh

Команда створює файл скрипта резервного копіювання.

#!/usr/bin/env bash
set -euo pipefail

source /root/.config/restic/dokploy-backup.env

BACKUP_DIR="/var/backups/dokploy"
STAMP="$(date +%F_%H-%M-%S)"
POSTGRES_CONTAINER="POSTGRES_CONTAINER"
POSTGRES_USER="POSTGRES_USER"
POSTGRES_DB="POSTGRES_DB"

mkdir -p "${BACKUP_DIR}/postgres"

docker exec "${POSTGRES_CONTAINER}" \
  pg_dump -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -Fc \
  > "${BACKUP_DIR}/postgres/${POSTGRES_DB}_${STAMP}.dump"

tar -czf "${BACKUP_DIR}/system_${STAMP}.tar.gz" \
  /etc/ssh \
  /etc/ufw \
  /etc/fail2ban \
  /etc/crontab \
  /root/server-inventory 2>/dev/null || true

restic backup "${BACKUP_DIR}" /etc/dokploy \
  --tag dokploy \
  --tag "$(hostname)"

restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

find "${BACKUP_DIR}" -type f -mtime +3 -delete

Скрипт створює PostgreSQL dump, архівує важливі системні налаштування, відправляє дані до Restic, застосовує політику зберігання та видаляє старі локальні тимчасові файли.

Якщо каталог /etc/dokploy відсутній у вашій інсталяції, видаліть його з команди restic backup і додайте фактичний шлях, знайдений на сервері. Перед автоматизацією виконайте скрипт вручну та переконайтеся, що він завершився без помилок.

sudo chmod 700 /usr/local/sbin/backup-dokploy.sh
sudo /usr/local/sbin/backup-dokploy.sh
sudo bash -c 'source /root/.config/restic/dokploy-backup.env && restic snapshots'

Команди призначають безпечні права, запускають перший бекап і показують створені snapshots.

Додайте розклад cron

sudo crontab -e

Команда відкриває root-crontab для запуску резервного копіювання за розкладом.

20 3   * /usr/local/sbin/backup-dokploy.sh >> /var/log/dokploy-backup.log 2>&1

Це cron-завдання запускає бекап щодня о 03:20 і зберігає вивід у лог.

Для production-бази логічний dump кращий за просте копіювання файлу volume під час роботи PostgreSQL. Файлова копія активної бази може бути неузгодженою. Для великих баз розгляньте реплікацію, WAL-архівацію, snapshot на рівні storage або керовану БД окремо від VPS із Dokploy.

Перевіряйте відновлення, а не лише наявність бекапу

Раз на місяць відновлюйте хоча б один PostgreSQL dump у тестову базу на окремому сервері або в ізольованому контейнері. Бекап без перевірки відновлення — це лише надія. Також переконайтеся, що пароль Restic зберігається не лише у файлі на production-сервері: збережіть його у password manager або захищеному аварійному наборі.

source /root/.config/restic/dokploy-backup.env
restic restore latest --target /tmp/dokploy-restore-test
find /tmp/dokploy-restore-test -maxdepth 3 -type f | head

Команди відновлюють останній snapshot до тимчасового каталогу та показують перші відновлені файли.

Оновлення Dokploy, Docker і системи

Оновлення бувають двох типів. Невеликі зміни застосунків зазвичай можна викочувати rolling deployment через Dokploy: нова версія запускається, проходить healthcheck, потім перемикається трафік. Оновлення самої платформи, Docker Engine, ядра Ubuntu та схеми бази даних краще виконувати в maintenance window, коли є свіжий бекап і можливість перевірити сервіси після перезавантаження.

  1. Перевірте статус сервісів і вільне місце на диску.
  2. Зробіть позаплановий бекап і переконайтеся, що snapshot з’явився у віддаленому сховищі.
  3. Прочитайте release notes Dokploy і Docker щодо breaking changes.
  4. За можливості спочатку оновіть staging-сервер.
  5. Оновіть Dokploy штатним способом, передбаченим поточною версією панелі.
  6. Перевірте панель, один критичний домен, логи та стан Swarm.
sudo apt update
apt list --upgradable
sudo docker service ls
sudo docker system df

Команди показують доступні оновлення ОС, стан сервісів і використання Docker-диска до початку робіт.

Не запускайте регулярно docker system prune -a --volumes через cron без розуміння наслідків. Ця команда може видалити невикористовувані volumes, build cache та образи, які можуть бути потрібні для швидкого rollback. Безпечніше спочатку використовувати docker system df, видалити свідомо непотрібні старі образи та зберігати кілька останніх робочих версій критичних сервісів.

Troubleshooting + FAQ

Чому панель Dokploy не відкривається на порту 3000?

Спочатку перевірте, що Docker активний: sudo systemctl status docker. Потім виконайте sudo docker service ls і curl -I http://127.0.0.1:3000. Якщо локальний curl працює, але браузер не підключається, проблема майже напевно в UFW, зовнішньому firewall провайдера або обмеженні доступу до 3000 за вашою IP-адресою. Перевірте sudo ufw status numbered і переконайтеся, що підключаєтеся з дозволеної адреси. Після перенесення панелі на HTTPS-домен зовнішній порт 3000 краще закрити.

Чому Let’s Encrypt не видає сертифікат для домену?

Перевірте DNS командою dig +short your-domain.example A: вона має повертати IP саме цього VPS. Потім переконайтеся, що ззовні доступні 80 і 443, а на них не слухає інший Nginx, Apache або Caddy. Помилка часто виникає через увімкнений CDN-proxy, неправильний AAAA-запис IPv6 або нещодавню зміну DNS, яка ще не поширилася. Перегляньте логи Traefik і deployment-логи в Dokploy. Не запитуйте сертифікат десятки разів поспіль: у Let’s Encrypt є ліміти спроб.

Деплой завершився успішно, але домен повертає 502 Bad Gateway. Що робити?

Помилка 502 означає, що reverse proxy не може отримати коректну відповідь від застосунку. Перевірте внутрішній порт у налаштуваннях Dokploy: він має збігатися з портом, який слухає процес усередині контейнера. Застосунок має слухати 0.0.0.0, а не лише 127.0.0.1. Перегляньте sudo docker service logs --tail 100 SERVICE_NAME; часто процес завершився через відсутню змінну DATABASE_URL, міграцію БД або помилку підключення до Redis.

Чому Dokploy не може клонувати приватний GitHub-репозиторій?

Перевірте спосіб автентифікації: GitHub App має бути встановлений саме для потрібного репозиторію, а deploy key має бути доданий до налаштувань конкретного repository. Під час SSH-автентифікації звіряйте private key у Dokploy із public key у GitHub. Не вмикайте write access, якщо сервіс лише читає код. Також переконайтеся, що clone URL відповідає вибраному способу: SSH URL починається з [email protected]:, а HTTPS URL потребує токена або GitHub App.

Збірка Docker падає з помилкою “no space left on device”. Як виправити?

Спочатку перегляньте вільне місце: df -h і sudo docker system df. Потім знайдіть великі каталоги через sudo du -xh /var/lib/docker | sort -h | tail. Видаляйте лише зрозумілі невикористовувані образи та кеш, а не volumes робочих баз даних. Оптимізуйте Dockerfile: використовуйте multi-stage build, .dockerignore, не копіюйте node_modules і не зберігайте великі артефакти у шарах. Якщо вільного місця менше 15–20 ГБ, збільште диск до наступного деплою.

Яка VPS-конфігурація мінімально підійде?

Для лабораторного проєкту можна почати з 1 vCPU, 2 ГБ RAM і 30–40 ГБ диска, але під час збірки Node.js, Next.js або Python-образів пам’ять швидко закінчиться. Практичний мінімум для production — 2 vCPU, 4 ГБ RAM і 50–80 ГБ NVMe. Це дозволяє запустити Dokploy, reverse proxy, один-два застосунки та невелику базу. Якщо на сервері є PostgreSQL і кілька сервісів, обирайте 4 vCPU та 8 ГБ RAM, щоб збірки не впливали на доступність користувачів.

Що обрати — VPS чи dedicated для цього завдання?

Для Dokploy і більшості невеликих production-застосунків обирайте VPS: його простіше масштабувати, він дешевший на старті та зазвичай надає достатньо ресурсів. Dedicated має сенс за постійного високого CPU-навантаження, великої PostgreSQL-бази, вимоги до гарантованих IOPS, десятків сервісів, що активно збираються, або потреби в сотнях гігабайтів швидких даних. Не переходьте на dedicated лише через одне разове падіння збірки: спочатку виміряйте CPU, RAM, disk I/O і фактичне навантаження.

Чи можна запускати PostgreSQL і Dokploy на одному VPS?

Так, для раннього етапу це нормальна та поширена схема. Обов’язково створіть persistent volume, налаштуйте регулярні логічні дампи й не дозволяйте базі займати весь диск. Стежте за пам’яттю: PostgreSQL, Docker build і SSR-застосунок можуть одночасно потребувати кілька гігабайтів RAM. Коли база стане критичною для бізнесу або навантаження зросте, винесіть її на окремий VPS, managed PostgreSQL або репліку з незалежними бекапами. Застосунок підключиться через приватну мережу або захищену публічну адресу.

Як безпечно очистити Docker після багатьох деплоїв?

Почніть із діагностики: sudo docker system df -v покаже, що займає місце. Видаляйте старі dangling-образи та непотрібний build cache вручну або штатними засобами Dokploy, якщо вони доступні у вашій версії. Перед очищенням створіть бекап і не видаляйте volumes, доки не знаєте, якому застосунку вони належать. Команда docker system prune -a --volumes агресивна та може видалити дані зупиненого, але все ще потрібного сервісу. У production спочатку виконуйте її лише без прапорця --volumes і аналізуйте список видалення.

Висновки та наступні кроки

Схема: Висновки та наступні кроки
Схема: Висновки та наступні кроки

Тепер VPS працює як власна платформа деплою: Dokploy отримує код із GitHub, збирає контейнери, публікує застосунки за доменами й обслуговує HTTPS. За правильного налаштування firewall, секретів і резервного копіювання такий стек підходить для невеликих production-сервісів і кількох командних проєктів.

  1. Створіть окремий staging-проєкт і прив’яжіть його до гілки develop, щоб перевіряти міграції та збірки до production.
  2. Додайте зовнішній моніторинг HTTP endpoint /health, сповіщення про недоступність і контроль вільного місця на диску.
  3. У міру зростання винесіть базу даних, object storage або workers на окремі вузли, а потім додайте другий Dokploy-вузол лише після проєктування мережі та стратегії відмовостійкості.

Головна практична рекомендація: автоматизуйте не лише деплой, а й відновлення. Регулярне тестування restore, оновлення в maintenance window і вимірювання реального споживання ресурсів забезпечують більше надійності, ніж просте збільшення розміру VPS.

Чи був цей гайд корисним?

Ваш відгук допомагає нам покращувати гайди.

Share this post:

Надішліть гайд тому, кому він може стати в пригоді.

Telegram VKVK WhatsApp Facebook LinkedIn XX

dokploy на vps: свій vercel/heroku для деплою з github
support_agent
Valebyte Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.