
Привет! Меня зовут Арсений Помазков. Я — разработчик и создатель одноименного YouTube-канала. Часто в pet-проектах приходится вручную загружать обновления на сервер. Это отнимает много времени и увеличивает вероятность ошибок при изменении кода. Чтобы упростить и ускорить процесс развертывания Telegram-бота, настроим автоматический деплой на сервер с помощью GitHub Actions.
Прежде всего вам понадобится Telegram-бот на любом языке. Я буду использовать пример из предыдущей инструкции о библиотеке Grammy JS. Вы можете создать собственный или использовать с GitHub — все ссылки оставлю в тексте.
Используйте навигацию, если не хотите читать текст полностью:
→ Подготовка бота
→ Настройка GitHub-репозитория
→ Автоматизация деплоя
→ Заключение
Подготовка бота
Чтобы использовать готовый код с GitHub, нужно убедиться, что на вашем компьютере установлен Git. Открываем командную строку и вводим команду:
git -v
Если видите актуальную версию Git, программа добавлена. В противном случае — скачиваете файл с официального сайта и устанавливаете.
Далее переходим в репозиторий, нажимаем на кнопку Code, выбираем HTTPS и копируем ссылку. В командной строке открываем папку с проектами и вводим команду:
git clone https://github.com/arseniypom/bot-automatization.git
В результате появится новая папка. Перетаскиваем ее в редактор кода и открываем командную строку, чтобы установить зависимости:
npm i
Внутри проекта находятся:
- node_modules — папка с файлами зависимостей;
- .gitignore — список файлов, которые мы не хотим заливать в Git;
- index.js — файл с кодом нашего бота;
- package-lock и package.json — список зависимостей.
В прошлой инструкции я рассказывал, как создать Telegram-бота с помощью Grammy JS, поэтому не буду подробно на нем останавливаться. Кратко пройдемся по основным шагам.
Создаем в проекте файл .env и добавляем в него переменную BOT_API_KEY:
BOT_API_KEY=0123456789:GHF3uhO16fM1Zqn7kyGIiYLuDSfDaNbr8mQ
Переменную можно назвать как угодно. Но поскольку в моем коде уже используется index.js, беру его.
Важно: полученный ключ позволяет управлять ботом, поэтому нигде его не публикуем.
Проверим, что все работает:
npm start
Переходим в Telegram по ссылке от @BotFather. Здесь простая механика: бот отвечает на команду /start и /menu, чтобы пользователь мог узнать статус заказа и обратиться в поддержку.

Тестовая версия Telegram-бота.
В демонстрационной части бот не реагирует на простые текстовые сообщения — весь функционал добавим в конце. Если хотите увидеть разбор функций, читайте предыдущую статью. Сейчас нас же интересует другое.

Настройка GitHub-репозитория
Итак, у нас есть рабочий бот. Загрузим его в свой репозиторий на GitHub. Если вы уже это сделали, переходите к следующему разделу. Если нет, пройдем весь процесс вместе.
Создаем новый репозиторий и указываем имя — в нашем случае bot-automatization-final. После — копируем HTTPS-ссылку:
https://github.com/arseniypom/bot-automatization-final.git
Переходим обратно в редактор. Поскольку мы скопировали бота из моего репозитория, у него уже есть связь с удаленным. Это можно проверить, введя команду:
git remote
В ответе видим название origin:

Теперь если введем команду git remote show origin, получим адрес этого репозитория.
git remote show origin

Далее используем команду git remote set-url origin и добавляем скопированную ссылку на только что созданный репозиторий:
git remote set-url origin https://github.com/arseniypom/bot-automatization-final.git
Перепроверяем результат командой git remote show origin. В ответе видим новый адрес:

Заливаем код на новый репозиторий:
git push origin main
Готово! Приступаем к деплою бота.
Деплой бота на сервер
Настройка сервера
Приступим к настройке сервера с помощью Github Actions. Для этого используем облачный сервер Selectel. Далее буду описывать весь процесс на его примере.
Переходим в панель управления и создаем аккаунт, если его нет. В левой секции выбираем Облачная платформа, регион Санкт-Петербург и пул ru-3. Нажимаем Создать сервер.
Указываем имя сервера как в репозитории и вводим нужные характеристики.
- Пул: ru-3b.
- Источник: любой дистрибутив Linux — Ubuntu, Debian, CentOS, Fedora и другие. В нашем случае — Ubuntu 64 512 Мб.
- Конфигурация: Shared. Итоговая конфигурация стоит от 10 ₽/день или около 300 ₽/месяц и подходит для небольших pet-проектов — например, Telegram-ботов и других.
В Shared Line можно арендовать не весь сервер, а его часть — 10, 20 или 50%. Выбираем 10% и наименьшую конфигурацию оперативки. Если получится так, что на сервере нет других арендаторов, все 100% мощности сервера переходят нам без доплат.
- Диск: базовый SSD на 5 ГБ.
- Сеть: новая публичная подсеть.
Еще один способ сэкономить на инфраструктуре — взять прерываемый облачный сервер. Он работает не более 24 часов, поэтому отлично подойдет для краткосрочных проектов. Стоимость ресурсов у такого сервера гораздо ниже.

Прерываемый сервер в конфигураторе.
При входе в консоль данные для входа отправляются автоматически, поэтому не настраиваем SSH-ключи и пароль. Нажимаем на кнопку Создать.
На странице нам открывается список всех серверов и их статус. Ждем, пока запуститься сервер. Как только статус переведется в Active, переходим к новому серверу. В открывшейся панели видим несколько вкладок и настройки, с помощью которых можно отключить или заморозить сервер. Дополнительно есть кнопка перезагрузки и другие опции.
Подключение к серверу
Ниже выбираем Консоль, вводим логин root и пароль. Настроить сервер можно прямо в консоли панели управления или через терминал компьютера по SSH. Будем использовать второй вариант.
Чтобы подключиться к компьютеру, нужно получить данные сервера. Пароль уже видели во вкладке Консоль, а IP — во вкладке Порты.

Сперва копируем IP-адрес. В терминале на Mac или командной строке на Windows вводим команду в формате ssh <имя пользователя>@<IP-адрес>. В нашем случае — ssh root@185.10.187.10.
После терминал отправляет вопрос: «Хотите ли вы продолжить подключение?» Изначально SSH-клиент не может проверить подлинность сервера, так как его ключ еще не сохранен на вашем компьютере. Пишем «yes», и при следующих попытках входа вопрос не появится.

Далее будет предложено ввести пароль. Копируем его из панели управления в разделе Консоль и вводим. Видим такой результат:

Снизу видим имя пользователя (root) и название сервера. Теперь можно настроить сервер для деплоя!
Деплой бота
Обновляем список пакетов в системе с помощью команды и устанавливаем нужные пакеты: git для работы с гитом, node.js и npm для запуска нашего приложения:
sudo apt install git nodejs npm
В ответе видим вопрос:
After this operation, 92.1 MB of additional disk space will be used.
Do you want to continue? [Y/n]
Отвечаем Y и нажимаем Enter. Убеждаемся, что все корректно работает:
node -v
npm -v
В результате видим рядом с каждой командой ее версию:

Система указывает 12 версию ноды, хотя актуальная на момент подготовки статьи – 20. Все потому, что версии этих пакетов по умолчанию старые. Нужно поставить пакет n и с его помощью самостоятельно установить стабильную версию.
sudo npm install -g n
sudo n stable
Повторно проверяем версию node с помощью node -v. Если все еще показывается старая версия, перезагружаем сервер. Это можно сделать кнопкой в правом верхнем углу или командой reboot прямо в консоли.

Раздел «Консоль» в настройках сервера.
Если выбрали перезагрузку через консоль, соединение будет разорвано. Нужно подождать пару минут, чтобы снова подключиться к серверу.
После ожидания вводим данные для входа и перепроверяем версии. Теперь они актуальные:

Загружаем менеджер процессов pm2, с помощью которого будем запускать бота. Устанавливаем его глобально — на это указывает флаг -g:
npm i pm2 -g
Далее клонируем репозиторий с ботом на сервер в формате git clone <ссылка на GitHub-репозиторий>:
git clone https://github.com/arseniypom/bot-automatization-final.git
После клонирование на сервере появляется папка с названием репозитория —заходим в нее:
cd bot-automatization-final
Для запуска осталось установить зависимости и создать файл .env с ключом бота. Последний включен в файл, поэтому отсутствует на сервере.
Устанавливаем зависимости:
npm i
Создаем файл .env и открываем с помощью редактора nano:
nano .env
После открытия редактора добавляем в него содержимое .env из проекта на компьютере:

Используем сочетанием клавиш Ctrl+O, затем Enter и Ctrl+X, чтобы сохранить прежнее имя файла и выйти из редактора.
Запускаем бота с помощью pm2. Не забудьте перед этим убедиться, что остановили его локально, иначе возникнут конфликты.
pm2 start index.js --name tg-bot
В консоли видим сообщение об успешном запуске:

Автоматизация деплоя
Для настройки деплоя используем GitHub Actions — встроенную в GitHub систему автоматизации, которая позволяет создавать и запускать рабочие процессы (workflow) для сборки, тестирования, деплоя и других задач. Запускаются они автоматически в ответ на события в репозитории — например, при пуше кода или создании pull request.
Возвращаемся в GitHub-репозиторий и переходим на вкладку Actions. На странице предложены уже готовые workflow — нам нужно создать собственный. Нажимаем на set up a workflow yourself.

В открывшийся редактор вставляем код:
name: Node.js CD # Название workflow (процесса автоматизации)
on:
push:
branches: [ main ] # Триггер: запускать workflow при пуше в ветку main
jobs:
build:
runs-on: ubuntu-latest # Определение окружения: используется последняя версия Ubuntu
steps:
- name: Deploy using ssh # Название шага: Деплой с использованием SSH
uses: appleboy/ssh-action@master # Использование готового действия для SSH-подключения
with:
host: ${{ secrets.HOST }} # Хост (сервер) для подключения, берется из секретов Github
username: ${{ secrets.USERNAME }} # Имя пользователя для SSH, берется из секретов Github
key: ${{ secrets.PRIVATE_KEY }} # Приватный ключ для SSH, берется из секретов Github
port: 22 # Порт для SSH-подключения (по умолчанию 22)
script: |
cd ~/bot-automatization-final # Переход в директорию с проектом на сервере
git pull origin main # Вытягивание последних изменений из ветки main
git status # Проверка состояния git-репозитория
npm install --only=prod # Установка только продакшн-зависимостей
pm2 restart tg-bot # Перезапуск процесса tg-bot с помощью PM2
Нажимаем на кнопку Commit changes… в правом верхнем углу. Повторяем действие в открывшемся окне.

В результате появится новый файл в репозитории с новым workflow ./github/workflows/main.yml.
Переходим в консоль, чтобы сгенерировать SSH-ключ на сервере:
ssh-keygen -t rsa -b 4096 -m PEM -C "github-actions-bot-automatization”
В ответ на вопрос о названии файла нажимаем Enter и оставляем название по умолчанию:
Enter file in which to save the key (/root/.ssh/id_rsa):
Повторяем действие на вопрос о секретной фразе и ее повторе – оставляем пустыми. Нажимаем Enter.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Получаем сообщение о создании ключа:

В итоге система автоматически сгенерировала два ключа: публичный и приватный. Они находятся в папке ~/.ssh.
Чтобы вывести публичный ключ в консоль, вводим команду:
cat ~/.ssh/id_rsa.pub
Ключ нужно скопировать и добавить в файл с authorized_keys:
nano ~/.ssh/authorized_keys
Добавляем публичный SSH-ключ и сохраняем сочетанием клавиш Ctrl+O, Enter и Ctrl+X.
Теперь уберем приватный SSH-ключ, чтобы добавить его в переменные окружения на GitHub:
cat ~/.ssh/id_rsa
Копируем значение вместе с фразами в начале и конце:
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEA1KcpcbZPKPyR8KGSo3qPJJ3IeTmkQxC1gohVyhl3R9h/KetB
CiczYsP0xnlM3ZMztfZYSqMNJy9811TDtT1s6I5sb1UJ9nz52T2qQPDBcSyUVwR5
...
wvT6Hy+I/5b4L89IkWcpSQcYg+SyBxMMVLliHDARfXmw5+jbFaG01854tOkvjD81
vJthoKSIwKgrAojmgiOF53/H+mHMUk4ckwRMsSJJuqEESBtxDzh7vmK0dWU=
-----END RSA PRIVATE KEY-----
Далее добавляем в GitHub. Для этого заходим в Settings→Secrets→Actions и нажимаем New repository secret.

Для ранее созданного workflow нужно три секретных ключа: PRIVATE_KEY, HOST и USERNAME. В блок Имя вписываем первую переменную PRIVATE_KEY, а в значение — приватный SSH-ключ. Нажимаем Add secret.

Также создаем оставшиеся переменные. В HOST помещаем IP-адрес сервера, а в USERNAME — root. Будьте внимательны, опечатки могут нарушить работу workflow.

Чтобы проверить бота, нужно внести изменения в код и запушить их в репозиторий.
Важно: перед тем, как использовать локальный репозиторий, необходимо подтянуть обновления из удаленного. Именно в нем создали новый файл с workflow — main.yml.
Обновляем репозиторий с помощью команды:
git pull origin main
Переходим к тестированию. Дописываем пару слов в приветственное сообщение:

Далее заливаем обновления на GitHub. Готово!

Заключение

Теперь если зайти во вкладку Actions на GitHub, мы увидим запуски workflow.

Система выполнила первый workflow сразу после создания файла main.yml. На момент создания мы «не добили» нужные секреты, поэтому они находятся в статусе Failed.
Второй запуск успешный. Произошел тогда, когда мы запушили изменения в ветку main из локального репозитория. Также workflow сработает, если добавим merge в главную ветку. На этом процесс автоматизации завершен!
Автор: Арсений Помазков, создатель YouTube-канала.
Автор: pomazkovjs