CI/CD на VPS через GitHub Actions: self-hosted runner и rsync
GitHub Actions умеет собирать и выкатывать код прямо на ваш VPS. Разберём два рабочих подхода: self-hosted runner для сборки на сервере и лёгкий rsync-деплой по SSH с облачных раннеров.
Содержание
Два подхода к деплою
['Есть два способа выкатывать код на VPS из GitHub Actions, и выбор зависит от того, где происходит сборка.', '- Self-hosted runner — агент GitHub на самом VPS. Сборка и тесты идут прямо на сервере, деплой сводится к перемещению файлов и рестарту сервиса. Удобно для тяжёлых сборок и приватных данных.
- rsync/SSH с облачного раннера — сборка на бесплатных раннерах GitHub, а на VPS попадает только готовый артефакт. Ничего лишнего на сервере не крутится.
Нужен сервер под эту задачу?
Разверните 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\nsu - runner\nmkdir actions-runner && cd actions-runner\ncurl -o actions-runner.tar.gz -L \\\n https://github.com/actions/runner/releases/download/v2.319.1/actions-runner-linux-x64-2.319.1.tar.gz\ntar xzf actions-runner.tar.gz\n./config.sh --url https://github.com/USER/REPO --token <TOKEN>', 'Токен из веб-интерфейса живёт около часа — если конфиг ругается на авторизацию, сгенерируйте новый. Дальше поставьте раннер как systemd-сервис, чтобы он поднимался после перезагрузки.', 'sudo ./svc.sh install runner\nsudo ./svc.sh start\nsudo ./svc.sh status']
Workflow для self-hosted runner
['Файл.github/workflows/deploy.yml. Раннер уже на сервере, поэтому деплой — это git pull, установка зависимостей и рестарт.', 'name: deploy\non:\n push:\n branches: [ main ]\njobs:\n deploy:\n runs-on: self-hosted\n steps:\n - uses: actions/checkout@v4\n - name: Build\n run: |\n npm ci\n npm run build\n - name: Restart service\n 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\non: { push: { branches: [ main ] } }\njobs:\n deploy:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - run: npm ci && npm run build\n - name: rsync to VPS\n run: |\n mkdir -p ~/.ssh\n echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_ed25519\n chmod 600 ~/.ssh/id_ed25519\n ssh-keyscan ${{ secrets.HOST }} >> ~/.ssh/known_hosts\n rsync -az --delete ./dist/ \\\n ${{ 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Частые вопросы
Self-hosted runner безопасен для публичного репозитория?
Нет. Для публичных репозиториев self-hosted runner опасен: чужой PR может выполнить код на вашем сервере. Используйте его только в приватных репозиториях.
Сколько ресурсов ест раннер в простое?
В простое агент почти не потребляет ресурсов — несколько десятков мегабайт RAM. Нагрузка появляется только на время сборки.
Можно ли деплоить без пересборки на сервере?
Да, вариант с rsync именно для этого: сборка на облачном раннере, на VPS уходит готовый артефакт.