Я устал деплоить проекты вручную и автоматизировал этот процесс

от автора

Проблема

Мне, как backend‑разработчику, приходится работать с деплоем своих проектов. Каждый раз одна и та же рутина: настройка сервера, Nginx, SSL, безопасность сервера(fail2ban, отдельный пользователь), CD и многое другое. Это забирает много времени.

Что сделал

После десятков задеплоенных проектов я понял, что все эти действия можно автоматизировать, и решил написать скрипт. Работает так: я запускаю скрипт и ввожу свои данные, которые уникальны у каждого проекта: домен, сервер, Docker, .env. Код этих bash‑скриптов я выложил в открытый репозиторий на GitHub, так что каждый может посмотреть, что выполняется на сервере, куда осуществляется деплой.

Конечно, в процессе работы со скриптами я сталкивался с ошибками, багами, недоработками.
Приведу пример с докером. При деплое на российских серверах у меня падала сборка Docker‑образов из‑за сетевых ограничений, поэтому я начал прописывать зеркала — тогда сборка стала быстрой и надёжной. Также при работе с внешними API запросы к сервисам были нестабильными, поэтому я прописал DNS‑серверы. Теперь всё надёжно и летает.

mkdir -p /etc/docker cat > /etc/docker/daemon.json <<‘JSON’ { “registry-mirrors”: [“https://mirror.gcr.io”, “https://dockerhub.timeweb.cloud”], “userland-proxy”: false, “dns”: [“8.8.8.8”, “1.1.1.1”] } JSON systemctl restart docker || true

С каждым разом я искал возможность автоматизации, потому что где‑то нужен мониторинг системы — Grafana + Prometeus. Их я решил поднимать в отдельном Docker Compose‑файле и запускать вместе с основным. Где‑то нужны защищённые роуты, в качестве VPN выбрал AmneziaWG, он простой в настройке и, как показывает практика, не блокируется. Поднимаем VPN, а в Caddyfile проверяем IP‑адрес запроса, если запрос из нашей сети — пропускаем, если нет — отдаём 404:

@protected {
path /путь /путь/ /путь/*
not remote_ip 10.8.0.0/24
}

respond @protected “404 Not Found” 404

Тут же расскажу про Caddy и почему я выбрал его, а не Nginx. Одно из преимуществ Caddy — автоматический SSL: про ручную настройку сертификатов можно практически забыть, и лёгкость конфигурации. В будущем, конечно, планирую перейти на Nginx: всё‑таки он проверен годами, да и при больших нагрузках может быть быстрее. Caddy поднимаю глобально на весь VPS, раньше он запускался в отдельном Docker‑контейнере. Это решение — вынести Caddy глобально — добавило возможность гибко им управлять при добавлении/удалении/обновлении проектов на 1 VPS. Caddyfile дефолтный, можно отметить наличие security‑заголовков:

header {
Strict-Transport-Security "max-age=31536000;"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
-Server
}

и подстановку реального IP и попытки достучаться до приложения, чтобы не отдавать пользователю 502:

reverse_proxy app-проект:порт {
header_up X-Real-IP {http.request.remote.host}
lb_try_duration 30s
lb_try_interval 250ms
}

Почему я сделал сервис, ведь уже есть готовые скрипты?

Эти bash‑команды либо писать вручную на VPS, либо писать программу, которая будет выполнять всё это на сервере, поэтому я, как веб‑разработчик, сделал UI для себя, где от меня требуется только заполнить форму и нажать кнопки, скрипт выполняется на сервере, где размещается проект(который мы ставим на хостинг). Помимо автоматизации, чтобы сервис не сидел без дела, пока работает проект, я постарался увеличить его КПД. Пусть пингует мой сервер каждые 20 секунд и выдаёт уведомление, если сервер не отвечает или отдаёт 500. А когда сервер восстановится (после обнаружения ошибки проверка идёт раз в 5 секунд), пусть тоже напишет. Также приходилось разрабатывать проекты командой и тут мой сервис был не готов конечно — все у одного человека. Пришлось добавить команды, где проекты общие — все участники видят лог: кто что нажал, когда CD отработал, когда был отключён и тому подобное

Про безопасность

Так как сервис работает с чужими серверами, я не хотел делать магию в стиле «просто доверься». Здесь есть несколько важных моментов.

Во‑первых, все запросы к самому сервису идут по HTTPS. Это закрывает передачу данных между браузером и сервисом, но понятно, что одного HTTPS недостаточно, потому что дальше остаются вопросы хранения данных, SSH‑доступ и выполнение команд на сервере.

Во‑вторых, сам деплой выполняется по SSH. То есть сервис не ставит на сервер какой‑то агент, который постоянно работает на сервере и ожидает команд, а подключается по SSH и выполняет нужные шаги во время деплоя. SSH в этом плане удобен тем, что уже решает задачу защищённого удалённого доступа.

.env я стараюсь не хранить в базе на постоянной основе. Он нужен на этапе деплоя, передаётся на сервер и используется уже там. Отдельно слежу, чтобы значения из .env не попадали в логи деплоя, потому что логами делюсь при отладке.

Доступ к GitHub нужен только на время получения кода для деплоя. Здесь тоже важно не записывать токены в логи и не хранить их в открытом виде. Из того, что всё‑таки нужно хранить постоянно: метаданные проекта, домен, репозиторий, настройки деплоя и зашифрованный приватный ключ для CD/откатов. Приватный ключ хранится не в чистом виде, а в зашифрованном виде через AES‑GCM. Это не делает систему неуязвимой, но защищает от самого тупого сценария, если кто‑то получит дамп базы, он не увидит ключи в открытом виде.

Понятно, что здесь ещё есть что улучшать: аудит действий, ротацию ключей, ограничения прав пользователя на сервере, более аккуратную работа с секретами и отдельные роли для команды. Но базовая идея такая: не хранить лишнее, не писать секреты в логи, передавать данные по защищённым каналам и показывать код скриптов, которые реально выполняются на сервере.

Что насчёт Dokku, Heroku, Railway и Render?

Эти инструменты отлично решают проблему деплоя, но всё равно это не то, что я хотел. Dokku хорош тем, что всё остаётся на твоём сервере. Но у меня всё равно оставалось ощущение, что я опять живу в терминале и вручную сопровождаю инфраструктуру. Heroku, Railway, Render и похожие сервисы удобны, но это уже их инфраструктура, ограничения и ценник. А мне хотелось немного другого: оставить проект на своём VPS, но сделать деплой таким же простым, как на PaaS‑платформах.

Кому интересен код, сервис:
Гитхаб с bash‑скриптами: https://github.com/slime4ik/djaploy‑scripts
Веб‑интерфейс, который вырос: https://djaploy.dev

ссылка на оригинал статьи https://habr.com/ru/articles/1054822/