MAATRIX / Блог / Автодеплой по webhook: push в GitHub обновляет сервер

Автодеплой по webhook: push в GitHub обновляет сервер

Блог MAATRIX · 2026-07-07

Каждый раз заходить по SSH и делать git pull — скучно и легко забыть. Настроим webhook: GitHub при каждом push дёргает наш сервер, тот проверяет подпись и сам обновляет код. Всё на чистом bash и systemd, без тяжёлых CI-платформ.

Как работает webhook-деплой

['Webhook — это HTTP-запрос, который GitHub отправляет на указанный URL при событии (обычно push). На сервере крутится маленький приёмник, который ловит этот запрос, проверяет, что он действительно от GitHub, и запускает скрипт деплоя: git pull, сборка, перезапуск сервиса.', '
  • Быстро — код на сервере через секунды после push.
  • Просто — не нужен Jenkins или GitLab Runner для маленького проекта.
  • Безопасно — проверка HMAC-подписи отсекает чужие запросы.
', 'Соберём приёмник на популярной утилите webhook (adnanh/webhook) — это один бинарник на Go, который слушает порт и запускает команды по правилам из YAML.']

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK и США. Оплата картой РФ и по СБП.

Арендовать VPS для автодеплоя

Ставим приёмник webhook

['В репозиториях Debian/Ubuntu есть готовый пакет, но свежее ставить бинарником с GitHub. Пакетный вариант проще всего.', '
sudo apt update && sudo apt -y install webhook
', 'Проверим, что бинарник на месте.', '
webhook -version
', 'Подготовим каталог проекта: клонируем репозиторий туда, где живёт сайт, чтобы деплой сводился к обновлению этой копии.', '
sudo mkdir -p /var/www/app\nsudo chown $USER:$USER /var/www/app\ngit clone git@github.com:user/repo.git /var/www/app
']

Скрипт деплоя

['Логику обновления вынесем в отдельный скрипт — так его легко тестировать вручную. Он подтягивает изменения и перезапускает сервис приложения.', '
sudo tee /var/www/deploy.sh > /dev/null <<\'EOF\'\n#!/usr/bin/env bash\nset -euo pipefail\ncd /var/www/app\ngit fetch --all\ngit reset --hard origin/main\n# npm ci && npm run build   # при необходимости\nsudo systemctl restart app.service\necho "Deployed $(git rev-parse --short HEAD)"\nEOF\nsudo chmod +x /var/www/deploy.sh
', 'git reset --hard origin/main вместо git pull надёжнее: он гарантирует, что рабочая копия точно совпадает с веткой, даже если на сервере кто-то случайно наследил в файлах.']

Правило webhook с проверкой подписи

['GitHub подписывает каждый запрос секретом через HMAC-SHA256 в заголовке X-Hub-Signature-256. Приёмник обязан проверить эту подпись — иначе любой сможет дёргать деплой. Опишем правило в JSON.', '
sudo tee /etc/webhook.conf > /dev/null <<\'EOF\'\n[\n  {\n    "id": "deploy",\n    "execute-command": "/var/www/deploy.sh",\n    "command-working-directory": "/var/www/app",\n    "trigger-rule": {\n      "and": [\n        { "match": { "type": "payload-hmac-sha256",\n          "secret": "MY_WEBHOOK_SECRET",\n          "parameter": { "source": "header", "name": "X-Hub-Signature-256" } } },\n        { "match": { "type": "value", "value": "refs/heads/main",\n          "parameter": { "source": "payload", "name": "ref" } } }\n      ]\n    }\n  }\n]\nEOF
', 'Второе условие match value refs/heads/main запускает деплой только на push в ветку main, игнорируя фичевые ветки.']

Запуск через systemd

['Чтобы приёмник жил после перезагрузки, обернём его в systemd-юнит. Слушать будем локальный порт, наружу проксировать через Nginx с TLS.', "
sudo tee /etc/systemd/system/webhook.service > /dev/null <<'EOF'\n[Unit]\nDescription=GitHub webhook receiver\nAfter=network.target\n\n[Service]\nExecStart=/usr/bin/webhook -hooks /etc/webhook.conf -port 9000 -verbose\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\nEOF\nsudo systemctl daemon-reload\nsudo systemctl enable --now webhook
", 'В настройках репозитория на GitHub (Settings → Webhooks) укажи Payload URL вида https://srv.example.com/hooks/deploy, Content type — application/json, Secret — тот же MY_WEBHOOK_SECRET. Проксируй /hooks/ в Nginx на http://127.0.0.1:9000.']

Безопасность и частые ошибки

['
  • Секрет обязателен — без проверки подписи webhook открыт для любого, кто узнает URL.
  • Не запускай деплой от root — заведи отдельного пользователя с правами только на каталог проекта.
  • Логируй — флаг -verbose и journalctl -u webhook помогут понять, почему деплой не сработал.
  • Таймаут на сборку — тяжёлый npm run build может подвесить приёмник; выноси долгие задачи в фоновый systemd-run.
', 'Проверить связку целиком просто: сделай тестовый push и посмотри логи. GitHub на вкладке Recent Deliveries показывает код ответа — 200 значит, что подпись прошла и скрипт запустился.', '
journalctl -u webhook -f
']

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK и США. Оплата картой РФ и по СБП.

Арендовать VPS для автодеплоя

Частые вопросы

Чем это лучше GitHub Actions?

Actions гоняет сборку в облаке и потом всё равно должен как-то попасть на сервер. Webhook-деплой обновляет сервер напрямую и не зависит от лимитов минут CI — для небольших проектов это проще и быстрее.

Что если сборка упала?

Скрипт с set -euo pipefail прервётся на ошибке и не перезапустит сервис с битым кодом. Стоит добавить откат на предыдущий коммит при неудачной сборке.

Можно ли деплоить без публичного порта?

Да — вместо приёмного webhook используй pull-модель: cron или GitHub Actions с self-hosted runner, который сам ходит за изменениями. Но входящий webhook быстрее реагирует на push.