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

Получить VPS arrow_forward
eco Начальный Туториал

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

calendar_month Sep 15, 2026 schedule 26 мин. чтения visibility 36 просмотров
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-фаундеру, небольшой команде или агентству, которое обслуживает несколько приложений. Один сервер может держать панель, 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.

Был ли этот гайд полезен?

Ваш отзыв помогает нам улучшать гайды.

Поделиться записью:

Отправьте гайд тому, кому он может пригодиться.

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.