Автоматический деплой на VPS через GitHub Actions — пошаговый гайд
Основной чат
Чат для вайбкодеров: новости, гайды, поиск исполнителей, маркетплейс и разбор реальных кейсов.
Вы написали код, ИИ помог, всё работает локально. Пора выкатить на сервер. Открываете терминал, подключаетесь по SSH, тянете git pull, перезапускаете процесс... и это нужно делать каждый раз. При каждом фиксе. При каждом обновлении.
Это не рабочий процесс — это ручной труд, который съедает время и рано или поздно приводит к ошибкам.
CI/CD (Continuous Integration / Continuous Deployment) — это когда сервер обновляется сам, как только вы делаете git push. Никаких SSH вручную, никакого «подождите, я задеплою». Запушил в main — через минуту новая версия живёт в проде.
В этом гайде — как настроить именно это: автодеплой на VPS через GitHub Actions и SSH, с нуля до рабочего пайплайна.
Что происходит «под капотом»
Когда вы настраиваете CI/CD с GitHub Actions, схема выглядит так:
Вы делаете git push в main
↓
GitHub замечает push
↓
GitHub Actions запускает runner (виртуальную машину)
↓
Runner подключается к вашему серверу по SSH
↓
На сервере выполняются команды: git pull, npm install, перезапуск
↓
Новая версия приложения работает в проде
Весь этот процесс — автоматически, за 30–90 секунд, каждый раз одинаково.
Что нужно перед началом
- Репозиторий на GitHub с вашим проектом.
- VPS с Ubuntu 22.04+ (подходит любой: Hetzner, DigitalOcean, Timeweb, REG.RU).
- Пользователь на сервере с правом запускать ваше приложение.
- Базовые знания SSH (уметь подключиться к серверу).
Шаг 1. Создать SSH-ключ для GitHub Actions
GitHub Actions будет подключаться к серверу как отдельный пользователь. Для этого нужна своя пара SSH-ключей — не та, которую вы используете лично.
На своём компьютере (не на сервере!) генерируем пару ключей:
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github_actions_deploy
Команда создаёт два файла:
~/.ssh/github_actions_deploy— приватный ключ (уйдёт в GitHub Secrets)~/.ssh/github_actions_deploy.pub— публичный ключ (уйдёт на сервер)
Шаг 2. Добавить публичный ключ на сервер
Подключитесь к серверу и добавьте публичный ключ в список авторизованных:
# На сервере: добавить публичный ключ
echo "ВСТАВЬТЕ_СОДЕРЖИМОЕ_ФАЙЛА_.pub" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
Содержимое файла github_actions_deploy.pub — одна длинная строка, которая начинается с ssh-ed25519. Скопируйте её целиком.
Проверьте, что подключение работает:
# На своём компьютере
ssh -i ~/.ssh/github_actions_deploy user@ваш-сервер-ip
Если подключились — ключи настроены правильно.
Шаг 3. Добавить секреты в GitHub
Перейдите в репозиторий на GitHub: Settings → Secrets and variables → Actions → New repository secret.
Добавьте три секрета:
| Имя секрета | Значение |
|---|---|
SSH_PRIVATE_KEY |
Содержимое файла github_actions_deploy (приватный ключ, целиком) |
SSH_HOST |
IP-адрес или домен вашего сервера |
SSH_USER |
Имя пользователя на сервере (например, ubuntu или deploy) |
Эти значения GitHub зашифрует и никогда не покажет в логах — даже если кто-то получит доступ к репозиторию, секреты останутся закрытыми.
Шаг 4. Создать workflow-файл
В корне репозитория создайте папку и файл:
.github/
└── workflows/
└── deploy.yml
Вот базовый workflow, который работает для большинства проектов:
name: Deploy to VPS
on:
push:
branches:
- main # запускается только при пуше в main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/my-project # путь к проекту на сервере
git pull origin main # тянем последние изменения
npm install --production # ставим зависимости
pm2 restart my-project # перезапускаем процесс
Замените /var/www/my-project на реальный путь к проекту на сервере, а my-project в pm2 restart — на имя вашего pm2-процесса.
Закоммитьте файл и запушьте в main. GitHub Actions запустится автоматически.
Смотреть, как деплой проходит
Откройте вкладку Actions в репозитории на GitHub. Там видно каждый запуск: какой шаг выполняется сейчас, логи каждой команды, итоговый статус (✓ или ✗).
Если что-то пошло не так — красный крестик, кликаете, видите точную строку с ошибкой. Не нужно гадать.
Готовые шаблоны под разные стеки
Node.js / Express
script: |
cd /var/www/my-project
git pull origin main
npm install --production
pm2 restart my-project
Next.js
script: |
cd /var/www/my-project
git pull origin main
npm install
npm run build
pm2 restart my-project
Python / Telegram-бот
script: |
cd /home/ubuntu/my-bot
git pull origin main
source venv/bin/activate
pip install -r requirements.txt
systemctl restart my-bot.service
Docker Compose
script: |
cd /var/www/my-project
git pull origin main
docker compose pull
docker compose up -d --build
Деплой только при успешных тестах
Если у вас есть тесты — запускайте деплой только когда они прошли. Это гарантирует, что сломанный код не попадёт на сервер:
name: Test and Deploy
on:
push:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install
- run: npm test # если тесты упали — деплой не запустится
deploy:
needs: test # ждёт успешного завершения job'а test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/my-project
git pull origin main
npm install --production
pm2 restart my-project
Деплой с уведомлением в Telegram
Хотите получать сообщение, когда деплой завершился — успешно или с ошибкой? Добавьте шаг в конец workflow:
- name: Notify Telegram
if: always() # отправляет и при успехе, и при ошибке
uses: appleboy/telegram-action@master
with:
to: ${{ secrets.TELEGRAM_CHAT_ID }}
token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
message: |
Деплой: ${{ job.status }}
Репозиторий: ${{ github.repository }}
Ветка: ${{ github.ref_name }}
Коммит: ${{ github.event.head_commit.message }}
Добавьте секреты TELEGRAM_BOT_TOKEN и TELEGRAM_CHAT_ID в GitHub Secrets — и после каждого деплоя будете получать отчёт в Telegram.
Отдельный пользователь для деплоя (правильно)
Подключаться как root для деплоя — плохая практика. Правильный подход: создать отдельного пользователя deploy с минимальными правами.
# На сервере
sudo useradd -m -s /bin/bash deploy
# Дать права на перезапуск нужных сервисов через sudo без пароля
echo "deploy ALL=(ALL) NOPASSWD: /bin/systemctl restart my-app" \
| sudo tee /etc/sudoers.d/deploy-restart
# Дать права на папку проекта
sudo chown -R deploy:deploy /var/www/my-project
После этого в секрете SSH_USER указывайте deploy, а не root.
Что делать, если деплой упал
Ошибка «Permission denied (publickey)»
Проблема с SSH-ключом. Проверьте:
- В секрете
SSH_PRIVATE_KEY— содержимое приватного ключа целиком (включая строки-----BEGIN...-----и-----END...-----). - Публичный ключ добавлен в
~/.ssh/authorized_keysна сервере. - Права на файл:
chmod 600 ~/.ssh/authorized_keys.
Ошибка «Host key verification failed»
GitHub Actions не знает fingerprint вашего сервера. Добавьте параметр в ssh-action:
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
host_key_algorithms: +ssh-rsa # или уберите строго если Ubuntu 22+
Или добавьте отдельный секрет SSH_HOST_KEY с fingerprint сервера (получить: ssh-keyscan ваш-сервер-ip).
Деплой прошёл, но сайт не обновился
Скорее всего pm2/systemd не перезапустился. Проверьте имя процесса:
pm2 list # имена всех процессов pm2
systemctl list-units # имена всех systemd-сервисов
Связь с другими статьями
Это базовый пайплайн — он закрывает 90% задач вайбкодера. Когда проект вырастет и вам понадобится деплой без единой секунды простоя и мгновенный откат — смотрите CI/CD для вайбкодинга: деплой без простоя и откат за 1 минуту, где разобрана Blue-Green стратегия поверх Docker.
Итог
Автодеплой через GitHub Actions — это инвестиция 30 минут один раз, которая экономит время при каждом следующем релизе. После настройки ваш рабочий цикл выглядит так:
написал код → git push → через минуту проект в проде
Больше не нужно помнить порядок команд, подключаться к серверу вручную или переживать, что забыли npm install. Actions делает это за вас — каждый раз одинаково.
Минимальный чеклист для первого деплоя:
- Сгенерировать SSH-ключ:
ssh-keygen -t ed25519 -f ~/.ssh/github_actions_deploy - Публичный ключ → в
~/.ssh/authorized_keysна сервере - Приватный ключ, хост, пользователь → в GitHub Secrets
- Создать
.github/workflows/deploy.ymlс нужным шаблоном - Запушить в
main→ открыть вкладку Actions → смотреть как работает