Раннеры GitHub-hosted — нормальный дефолт. Они перестают быть нужны в момент, когда сборке нужно то, чего у них нет: ваш приватный реестр пакетов, конкретная версия тулчейна, которую надоело переустанавливать каждый прогон, база в вашей сети или просто больше контроля над машиной. Вот тогда self-hosted раннер на VPS оправдывает себя.
Этот гайд поднимает его как надо: установлен, зарегистрирован, жив под systemd и — та часть, в которой ошибаются, — безопасен. Начнём с последнего, потому что именно это кусается.
Единственное правило безопасности
Воркфлоу GitHub Actions выполняет произвольный код — всё, что в файле воркфлоу, и всё, что этот код тянет. На вашем репо это ваш код, и всё нормально. На публичном репо pull request от чужака может выполнить его код на вашем раннере. Это не баг; так устроен CI. Документация GitHub прямо говорит: не используйте self-hosted раннеры с публичными репозиториями.
Так что правило простое и без исключений: self-hosted раннеры — для приватных репо. Если репозиторий публичный, используйте GitHub-hosted раннеры и не думайте. Всё ниже предполагает приватный репозиторий.
Что раннеру нужно от машины
Зависит от сборки, и считать надо под свою, а не по цифре со страницы:
- Типичная задача «собрать и протестировать» — 2 ядра и 4-8 ГБ комфортны. Small ($8, 4 vCPU / 4 ГБ) или Medium ($12, 6 vCPU / 6 ГБ) покрывают большинство.
- Тяжёлые сборки — крупная нативная компиляция, сборка больших Docker-образов, прожорливые тест-сьюты — просят больше запаса. Посмотрите один реальный прогон (
htopво время сборки) и считайте по тому, что реально видите, а не по надежде.
Диск тоже важен: кеши сборки, слои Docker и склонированные репо накапливаются. Держите на глазу и чистите.
1. Подготовить машину
Создайте не-root пользователя для раннера — установщик GitHub всё равно откажется работать под root, и это правильно:
sudo adduser --disabled-password --gecos "" runner
sudo usermod -aG sudo runner # только если сборкам реально нужен sudo
Поставьте то, что нужно сборкам — тулчейн языка, Docker, инструменты сборки. Например, если задачи собирают контейнеры:
sudo apt update && sudo apt install -y docker.io
sudo usermod -aG docker runner
2. Скачать и зарегистрировать раннер
В вашем репо (или организации) на GitHub зайдите в Settings → Actions → Runners → New self-hosted runner. GitHub выдаст точные команды загрузки и токен регистрации (он короткоживущий — берите свежий). Под пользователем runner:
sudo -iu runner
mkdir actions-runner && cd actions-runner
# используйте точный URL, который GitHub показал под вашу ОС/архитектуру:
curl -o actions-runner-linux-x64.tar.gz -L "URL_ОТ_GITHUB"
tar xzf actions-runner-linux-x64.tar.gz
./config.sh --url https://github.com/ВАША_ORG/ВАШ_REPO --token ВАШ_ТОКЕН
config.sh спросит имя раннера, метки и рабочую папку — для старта дефолты подойдут. Метки — то, как воркфлоу нацеливается на этот раннер (runs-on: self-hosted).
3. Запустить как сервис systemd
Раннер идёт с помощником, который ставит сервис systemd за вас — используйте его, чтобы раннер переживал перезагрузки и рестартовал при падении. Всё под установкой пользователя runner, но команды сервиса требуют root:
sudo ./svc.sh install runner
sudo ./svc.sh start
sudo ./svc.sh status
Это регистрирует actions.runner.* как unit systemd, работающий от пользователя runner, со стартом при загрузке. Логи идут в journald:
sudo journalctl -u 'actions.runner.*' -f
Обратно на странице Runners в GitHub ваш раннер теперь показывает Idle — зелёная точка. Нацельте на него воркфлоу:
jobs:
build:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- run: make test
Пушьте — и задача выполнится на вашей машине.
4. Держать в чистоте
Self-hosted раннер переиспользует свою файловую систему между задачами — это выигрыш в скорости (тёплые кеши) и грабли (остаточное состояние). Две привычки держат его здоровым:
- Регулярно чистите. Особенно Docker —
docker system pruneпо крону, иначе диск тихо забивается мёртвыми слоями. - Не храните секреты на машине. Используйте secrets GitHub Actions, инжектящиеся на каждый прогон, а не файлы в домашней папке раннера. Если раннер скомпрометируют, всё на диске уйдёт вместе с ним.
Если нужно по-настоящему чистое окружение на каждую задачу — запускайте каждую внутри шага-контейнера: раннер остаётся, а мусор задачи — нет.
Когда self-host, честно
Self-host, когда нужен свой тулчейн вшитым, доступ к приватным ресурсам сети или контроль над машиной. Оставайтесь на GitHub-hosted раннерах, когда чистое одноразовое окружение и их минуты вас устраивают — это правда проще, а простота чего-то стоит. И никогда, на публичном репо, не делайте self-host. Это не вопрос предпочтений.
Если нужен раннер под приватный репо: выберите тариф — Small ($8) для лёгких сборок, Medium ($12), когда тяжелеют, — оплатите в USDC или USDT (без KYC, без документов), и root будет примерно за 60 секунд. Дальше идите по этой странице — и через пару минут раннер начнёт подхватывать задачи.