Как разместить Telegram-бота на Node.js: хостинг и деплой
Telegram-бот на Node.js готов и работает локально: запущен node bot.js, отвечает на сообщения. Но локальный запуск живёт ровно до закрытия терминала или выключения ноутбука. Чтобы бот отвечал круглосуточно, его нужно разместить там, где процесс работает постоянно. Разберём варианты хостинга, подготовку к деплою и сам деплой.
Long-polling или webhook
Это первое решение, и от него зависит, какой хостинг подойдёт.
Long-polling: бот сам постоянно опрашивает Telegram методом getUpdates. Ему не нужен публичный домен, SSL или открытый входящий порт — достаточно исходящего соединения в интернет. В Telegraf это режим по умолчанию (bot.launch()), в grammY — bot.start(). Для большинства ботов его более чем достаточно.
Webhook работает наоборот: Telegram сам присылает обновления на HTTPS-эндпоинт бота. Нужны публичный домен, валидный SSL-сертификат и открытый порт (Telegram принимает только 443, 80, 88 или 8443). Webhook эффективнее под высокой нагрузкой и удобнее, когда нужно несколько инстансов за балансировщиком.
Практический вывод: начинать стоит с long-polling, а переходить на webhook, когда нагрузка реально этого требует. Важная деталь: одновременно работает либо одно, либо другое. Два параллельных long-polling-процесса с одним токеном дадут 409 Conflict: terminated by other getUpdates request.
Куда размещать: варианты
- VPS (Beget, Timeweb, Hetzner). Полный контроль над сервером. Минус: всё придётся настроить и обслуживать самому — установить Node.js, поднять менеджер процессов для автозапуска, развернуть базу, настроить бэкапы и SSL для webhook. Дёшево по деньгам, дорого по времени.
- Готовый Docker VPS (DockerVPS.ru). VPS с предустановленными Docker и панелью управления контейнерами — от 99 ₽/мес. Ставите только код бота, без ручной установки окружения и менеджера процессов.
- Хостинг ботов (bothost.ru). Деплой из Git: платформа сама собирает проект, держит процесс запущенным и перезапускает после сбоя, а рядом поднимается managed-база. Оплата российской картой, серверы в РФ и Европе, тест 7 дней без карты. Меньше ручной работы ценой меньшей гибкости в настройке ОС.
- Managed-платформа (PaaS, Railway, Render). Тот же git push и автозапуск, но зарубежные платформы: проблемы с оплатой из РФ и риск блокировки.
- Serverless (облачные функции). Для ботов обычно не подходит: long-polling требует постоянно живущего процесса, которого в serverless нет; webhook-функции возможны, но страдают от cold start и лимитов времени выполнения.
Подготовка бота к деплою
Эти шаги нужны при любом хостинге.
Зафиксировать зависимости. Зависимости должны быть перечислены в package.json, а package-lock.json закоммичен: по нему npm ci ставит точные версии. Сам каталог node_modules в репозиторий не кладут — он указывается в .gitignore.
Вынести токен и секреты из кода. Токен бота нельзя держать в исходниках и тем более коммитить в Git — его читают из переменных окружения:
const TOKEN = process.env.BOT_TOKEN;
if (!TOKEN) throw new Error("BOT_TOKEN is not set");
Локально переменные удобно держать в файле .env (через пакет dotenv или встроенный флаг node --env-file=.env bot.js в Node.js 20.6+) и добавить .env в .gitignore. На сервере те же переменные задаются в окружении процесса. Если токен всё же попал в публичный репозиторий — немедленно отозвать через @BotFather и выпустить новый.
Не хранить состояние в памяти. Данные пользователей, сессии и очереди при хранении в обычных переменных JavaScript теряются при каждом рестарте и редеплое. Под состояние нужна внешняя база: Postgres или Redis. Иначе бот будет «забывать» пользователей после каждого перезапуска.
Деплой на VPS
Кратко: забрать код, установить зависимости, запустить под менеджером процессов.
git clone https://github.com/user/mybot.git /opt/mybot
cd /opt/mybot
npm ci # точные версии из package-lock.json
Запускать node bot.js руками нельзя: процесс умрёт с закрытием сессии. Для Node.js идиоматичен pm2, который держит бот запущенным и поднимает после сбоя:
npm install -g pm2
pm2 start bot.js --name mybot
pm2 startup # зарегистрировать автозапуск при перезагрузке
pm2 save # зафиксировать список процессов
Без pm2 save после перезагрузки сервера список окажется пустым.
Деплой на хостинг ботов / managed-платформу
Сценарий короче: подключить репозиторий, задать переменные окружения (включая BOT_TOKEN) в панели и нажать «Обновить из Git» (или сделать git push). Платформа определит по package.json, что это Node.js-проект, выполнит npm ci, запустит стартовый скрипт (scripts.start, например node bot.js) и будет держать процесс живым без отдельной настройки менеджера процессов. Managed-база, а для webhook домен с SSL, поднимаются рядом и не требуют ручной возни.
Проверка после деплоя
Бот задеплоен, но «задеплоен» не значит «работает». Стоит убедиться явно:
- посмотреть логи процесса: при старте не должно быть исключений, а long-polling-бот сообщает, что начал получать обновления;
- отправить боту /start в Telegram и дождаться ответа;
- проверить, что токен виден процессу: метод getMe возвращает данные бота, а не ошибку 401 Unauthorized:
curl https://api.telegram.org/bot<BOT_TOKEN>/getMe
Если бот молчит, причина почти всегда одна из трёх: токен не попал в окружение процесса (или устарел), бот слушает не тот порт для webhook, либо в логах исключение на старте. Разбор каждой — в логах и ответе getMe.
FAQ
Что выбрать — long-polling или webhook?
Начинайте с long-polling: он проще и не требует домена и SSL. На webhook переходите под высокой нагрузкой (от пары сотен активных пользователей в сутки), когда нужна меньшая задержка и эффективнее ресурсы. Одновременно они работать не могут — будет ошибка 409 Conflict.
Как держать Node.js-бота запущенным?
На VPS — pm2 (pm2 start + pm2 startup + pm2 save) или systemd. На хостинге ботов и PaaS процесс держит платформа: она сама перезапускает бота после сбоя и перезагрузки.
Что делать, если бот не отвечает после деплоя?
Проверьте три вещи: токен в переменных окружения (getMe должен вернуть данные бота, а не 401), порт для webhook, и логи на старте — нет ли исключения. В 90% случаев дело в токене или порте.
Обязательно ли хранить состояние в базе?
Да, если бот помнит пользователей, сессии или очереди: память JavaScript очищается при каждом рестарте. Под состояние нужен Postgres или Redis — иначе после перезапуска бот «забывает» всех.
_Статья обновлена 31 августа 2026 по материалам каталога ServerScan._