CI/CD на VPS через GitHub Actions: self-hosted runner и rsync
GitHub Actions умеет собирать и выкатывать код прямо на ваш VPS. Разберём два рабочих подхода: self-hosted runner для сборки на сервере и лёгкий rsync-деплой по SSH с облачных раннеров.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Два подхода к деплою
Есть два способа выкатывать код на VPS из GitHub Actions, и выбор зависит от того, где происходит сборка.
- Self-hosted runner — агент GitHub на самом VPS. Сборка и тесты идут прямо на сервере, деплой сводится к перемещению файлов и рестарту сервиса. Удобно для тяжёлых сборок и приватных данных.
- rsync/SSH с облачного раннера — сборка на бесплатных раннерах GitHub, а на VPS попадает только готовый артефакт. Ничего лишнего на сервере не крутится.
Для стабильной сборки важен быстрый диск и предсказуемое CPU: на AMD EPYC + NVMe у MAATRIX self-hosted runner собирает проект заметно быстрее, чем на дешёвом OpenVZ с плавающей нагрузкой.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
Арендовать VPS для CI/CDВариант 1: self-hosted runner
В репозитории откройте Settings → Actions → Runners → New self-hosted runner, выберите Linux x64 и скопируйте команды. На VPS создайте отдельного пользователя и разверните агента.
adduser --disabled-password --gecos "" runner
su - runner
mkdir actions-runner && cd actions-runner
curl -o actions-runner.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.319.1/actions-runner-linux-x64-2.319.1.tar.gz
tar xzf actions-runner.tar.gz
./config.sh --url https://github.com/USER/REPO --token <TOKEN>
Токен из веб-интерфейса живёт около часа — если конфиг ругается на авторизацию, сгенерируйте новый. Дальше поставьте раннер как systemd-сервис, чтобы он поднимался после перезагрузки.
sudo ./svc.sh install runner
sudo ./svc.sh start
sudo ./svc.sh status
Workflow для self-hosted runner
Файл .github/workflows/deploy.yml. Раннер уже на сервере, поэтому деплой — это git pull, установка зависимостей и рестарт.
name: deploy
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: Build
run: |
npm ci
npm run build
- name: Restart service
run: sudo systemctl restart myapp
Чтобы systemctl restart работал без пароля, добавьте пользователю точечное правило в sudoers через visudo -f /etc/sudoers.d/runner:
runner ALL=(ALL) NOPASSWD: /bin/systemctl restart myapp
Вариант 2: rsync-деплой по SSH
Сборка идёт на облачном раннере, на VPS уезжает только каталог dist. Сгенерируйте отдельный SSH-ключ для деплоя и положите публичную часть в ~/.ssh/authorized_keys на сервере, а приватную — в секреты репозитория (SSH_KEY, HOST, USER).
ssh-keygen -t ed25519 -C "gh-deploy" -f deploy_key -N ""
name: deploy
on: { push: { branches: [ main ] } }
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- name: rsync to VPS
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan ${{ secrets.HOST }} >> ~/.ssh/known_hosts
rsync -az --delete ./dist/ \
${{ secrets.USER }}@${{ secrets.HOST }}:/var/www/app/
Флаг --delete удаляет на сервере файлы, которых больше нет в сборке — так каталог всегда точно повторяет артефакт. Root-доступ на VPS MAATRIX позволяет сразу настроить права и пользователя деплоя без запросов в поддержку.
Отдельный совет: не деплойте под root. Заведите пользователя deploy с доступом только к каталогу приложения и точечным правом на рестарт сервиса. Так утечка деплой-ключа не даст злоумышленнику весь сервер, а лишь ограниченную роль. Ключ деплоя держите отдельным от вашего личного SSH-ключа и при компрометации меняйте только его.
После деплоя полезно дёрнуть уведомление в мессенджер — тогда команда сразу видит, какой коммит уехал в прод. В GitHub Actions это делается дополнительным шагом с curl на вебхук Telegram или Slack.
Частые ошибки
- Раннер offline после ребута — забыли
svc.sh install, агент запускался только вручную. - Permission denied при рестарте — нет правила в sudoers или опечатка в имени сервиса.
- Host key verification failed — не выполнили
ssh-keyscan, ключ хоста неизвестен раннеру. - rsync снёс лишнее —
--deleteс неверным путём назначения. Всегда указывайте конечный слэш в путях.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
Арендовать VPS для CI/CDОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Self-hosted runner безопасен для публичного репозитория?
Нет. Для публичных репозиториев self-hosted runner опасен: чужой PR может выполнить код на вашем сервере. Используйте его только в приватных репозиториях.
Сколько ресурсов ест раннер в простое?
В простое агент почти не потребляет ресурсов — несколько десятков мегабайт RAM. Нагрузка появляется только на время сборки.
Можно ли деплоить без пересборки на сервере?
Да, вариант с rsync именно для этого: сборка на облачном раннере, на VPS уходит готовый артефакт.