Чтобы запустить бота grammY 24/7, его нужно держать на машине, которая всегда включена: на Linux VPS со службой systemd, которая запускает его снова после остановки, или на тарифе для ботов PlayNHost (от US$1.99 в месяц), где панель устанавливает ваши пакеты, передаёт коду токен и перезапускает бота после сбоя. В нашем тесте бот на grammY 1.46.0 занимал около 60 МБ памяти на Node.js 22. bot.start() в grammY использует long polling, и именно он нужен нашим тарифам: у них пока нет публичного HTTPS-адреса для вебхука. Шаги в PlayNHost:
- На странице хостинга Telegram-ботов нажмите Создать сервер у нужного тарифа. В окне заказа на вопрос Для какой платформы ваш бот? ответьте Telegram и выберите Node.js.
- Откройте свой сервер в панели. Карточка Настройка бота на странице Обзор открывается на шаге Подключение к Telegram; его первый шаг, Что запускается, должен показывать Этот бот запускает Node.js Bot.
- В разделе Подключение к Telegram вставьте токен от @BotFather в поле Вставьте токен бота, нажмите Подключение, проверьте показанное имя бота и нажмите Да, продолжить.
- В разделе Ваш код нажмите Загрузить файлы и загрузите
package.jsonиindex.jsбезnode_modulesили нажмите Подключить Git. Кода ещё нет? Создать стартового бота напишет для вас небольшого бота на grammY. - На странице Бот, во вкладке Код, проверьте, что Файл запуска указывает на файл, который запускает вашего бота (по умолчанию
index.js). Если вы его меняете, нажмите Сохранить. - Нажмите Запустить бота и откройте Console. При первом запуске npm установит grammY, затем бот выведет
Logged in as @your_bot, и индикатор на странице Обзор сменится на Онлайн в Telegram. - На странице Бот, во вкладке Telegram, нажмите Открыть в Telegram и отправьте боту
/start.
Как создать бота в @BotFather и что делают шаги в панели, объяснено в статье Как запустить Telegram-бота на хостинге. Эта страница посвящена самому grammY: что он использует на сервере и что нужно знать перед запуском.
Что мы измерили
| Библиотека | Версия | Память в покое | От запуска до ответа Telegram | Размер установки |
|---|---|---|---|---|
| grammY | 1.46.0 | 60 МБ | 0,2 с | 3,0 МБ |
| Telegraf | 4.16.3 | 60 МБ | 0,2 с | 2,7 МБ |
| node-telegram-bot-api | 2.3.0 | 63 МБ | 0,2 с | 2,4 МБ |
| Только Node.js 22, без библиотеки | 22.23.4 | 43 МБ | нет | нет |
Как мы измеряли: на нашем собственном узле, в одноразовом контейнере, настроенном как тариф для ботов на 1 ГБ (образ Node.js 22 и команда запуска нашего типа бота Node.js, с лимитом памяти Node на уровне 80 процентов), каждый бот обращался к Telegram с поддельным токеном, который Telegram отклонял. Память это резидентная память через 15 секунд после этого ответа, время запуска считается от старта до ответа, а каждое значение это медиана запусков со 2-го по 4-й.
Это нижние границы: бот без чатов и пока без данных. Ваш собственный код, то, что он хранит в памяти, и число чатов добавляются к ним, поэтому библиотека занимает лишь малую часть тарифа STARTER на 0,5 ГБ.
Минимальный бот на grammY
Он отвечает на /start, читает токен, который передаёт панель, и выводит строку о готовности. Положите оба файла в главную папку бота.
package.json
{
"name": "my-grammy-bot",
"private": true,
"main": "index.js",
"dependencies": {
"grammy": "^1.46.0"
}
}
index.js
const { Bot, GrammyError } = require("grammy");
const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN);
bot.command("start", (ctx) => ctx.reply("Hello! I am running on PlayNHost."));
// Without this, an error in one command stops the whole bot.
bot.catch((err) => {
console.error(`Error while handling update ${err.ctx.update.update_id}:`, err.error);
});
// bot.start() only returns when the bot stops, so the ready line goes in onStart.
bot.start({
onStart: (me) => console.log(`Logged in as @${me.username}`),
}).catch((err) => {
if (err instanceof GrammyError && err.error_code === 401) {
console.log("Telegram did not accept the bot token. Paste the current one from @BotFather, then restart.");
} else {
console.error(err);
}
process.exit(1);
});
Панель передаёт коду токен как TELEGRAM_BOT_TOKEN, а также как BOT_TOKEN, TOKEN, TELEGRAM_TOKEN и TELOXIDE_TOKEN, поэтому process.env.BOT_TOKEN из других примеров тоже работает. Именно строка Logged in as @your_bot переключает индикатор на Онлайн в Telegram.
Если токен неверный
В нашем тесте с поддельным токеном bot.start() в grammY завершился с такой ошибкой:
GrammyError: Call to 'deleteWebhook' failed! (401: Unauthorized)
bot.start() отправляет getMe и deleteWebhook одновременно, поэтому в ошибке указан тот вызов, который Telegram отклонил первым: в некоторых наших запусках это был Call to 'getMe' failed! (401: Unauthorized). grammY не повторяет запрос с отклонённым токеном: bot.start() сразу завершается ошибкой. Бот выше перехватывает этот случай и вместо этого выводит Telegram did not accept the bot token. Paste the current one from @BotFather, then restart., а панель показывает баннер Telegram не принял токен вашего бота над окном Console. Чтобы исправить, отправьте в @BotFather команду /mybots, выберите бота, затем API Token и снова скопируйте токен. На странице Бот, во вкладке Telegram, нажмите Заменить токен, вставьте его, нажмите Сохранить токен, затем Перезапустить сейчас.
Что нужно знать о grammY на сервере
- Строка о готовности должна быть в
onStart.bot.start()возвращается только тогда, когда бот останавливается, поэтомуconsole.logпослеawait bot.start()не выводится, пока бот работает. grammY вызываетonStartс данными вашего бота прямо перед тем, как запросить у Telegram первые сообщения. - Ошибка в команде останавливает бота, если не задан
bot.catch. Без него grammY выводитNo error handler was set!, останавливает polling и выбрасывает ошибку, поэтому процесс завершается. Наша панель перезапускает упавшего бота примерно через минуту, но до этого он офлайн. Сbot.catch, как выше, ошибка выводится, а бот продолжает работать. - Оставшийся на боте вебхук удаляется за вас.
bot.start()вызываетdeleteWebhookперед polling и сохраняет ожидающие сообщения, если не передатьdrop_pending_updates: true. Это важно, когда вы переносите бота с хостинга, который использовал вебхук: Как перенести Telegram-бота на PlayNHost. - Вторая копия бота останавливает эту. При
409 Conflict(тот же токен опрашивает Telegram в другом месте)bot.start()завершается ошибкой вместо повтора. Панель показывает Ваш бот работает ещё и в другом месте: остановите копию на своём компьютере или на старом хостинге. См. Как исправить ошибку 409 Conflict у Telegram-бота. - Сетевые ошибки при запуске повторяются без вывода. Если первый вызов Telegram не удаётся из-за сети, grammY пробует снова с всё более длинными паузами (до 20 минут между попытками в версии 1.46.0) и ничего не выводит. Чтобы увидеть эти попытки, на странице Бот, во вкладке Окружение, добавьте переменную
DEBUGсо значениемgrammy*(Добавить переменную) и перезапустите бота. - Версия Node.js: для grammY 1.46.0 нужен Node.js 12.20 или 14.13.1 и новее. В поле Среда выполнения во вкладке Код доступны Node.js 20, 22 (recommended), 24, 25 и 26.
- Лимит памяти: скрипт запуска задаёт
NODE_OPTIONS=--max-old-space-sizeравным 80 процентам памяти вашего тарифа, чтобы остальной части процесса хватало места. Подробности о скрипте запуска Node.js: Как запустить Discord-бота на Node.js.
Запуск на своём Linux VPS
На Debian 12 или 13 либо Ubuntu 24.04 для grammY достаточно пакета из репозитория дистрибутива (в Debian 12 это Node.js 18.20, в Debian 13 это 20.19, в Ubuntu 24.04 это 18.19):
sudo apt update
sudo apt install nodejs npm
node --version
Создайте пользователя для бота, скопируйте файлы и установите пакеты:
sudo useradd --system --create-home --home-dir /opt/mybot mybot
sudo cp package.json index.js /opt/mybot/
sudo chown -R mybot: /opt/mybot
cd /opt/mybot && sudo -u mybot npm install --omit=dev
Храните токен вне кода, в файле, который может читать только root:
sudo sh -c 'echo "TELEGRAM_BOT_TOKEN=123456789:your-token" > /etc/mybot.env'
sudo chmod 600 /etc/mybot.env
Создайте /etc/systemd/system/mybot.service:
[Unit]
Description=grammY Telegram bot
Wants=network-online.target
After=network-online.target
[Service]
User=mybot
WorkingDirectory=/opt/mybot
EnvironmentFile=/etc/mybot.env
ExecStart=/usr/bin/node index.js
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Запустите службу сейчас и при каждой загрузке, затем следите за её выводом:
sudo systemctl daemon-reload
sudo systemctl enable --now mybot
sudo journalctl -u mybot -f
Restart=always запускает бота снова после сбоя или после process.exit(1). Сначала остановите любую другую копию, иначе Telegram ответит обеим ошибкой 409 Conflict.
Свой сервер или тариф для ботов
На VPS, которым вы управляете сами, на вас лежит:
- Обновление и безопасность операционной системы, а также обновление Node.js.
- Запуск
npm installпосле каждого изменения, файл службы, файл с токеном и его права доступа. - Чтение
journalctl, чтобы понять, почему бот остановился. - Резервные копии данных бота.
Взамен VPS запускает что угодно, и ему можно назначить домен с HTTPS для вебхука.
На тарифе для ботов PlayNHost это делает панель:
- Выбор версии Node.js и
npm install, когда меняютсяpackage.json, lock-файл или версия Node.js. - Токен проверяется в Telegram до сохранения, хранится в зашифрованном виде и передаётся вашему коду.
- Перезапуск бота после сбоя. Если он падает снова в течение минуты, он остаётся остановленным, а Console показывает причину.
- Баннеры над окном Console, которые называют причину, если Telegram отклоняет токен, работает другая копия или задан вебхук, с кнопкой Удалить вебхук во вкладке Telegram.
- Загрузка файлов, деплой из Git и резервные копии прямо из панели.
См. также Как использовать базу данных MySQL с ботом grammY (mysql2).
Частые вопросы
Это то же самое, что стартовый бот панели?
Почти. На сервере Node.js Создать стартового бота записывает index.js и package.json с grammY ^1.46.0: бот отвечает на /start вашим именем, выводит Logged in as @your_bot, перехватывает ошибки через bot.catch и выводит понятную строку, когда Telegram отклоняет токен. Измените его как хотите и перезапустите.
Нужно ли удалять вебхук перед bot.start()?
Нет. bot.start() удаляет его через deleteWebhook перед polling, а ожидавшие сообщения сохраняются. Если ваш прежний код использовал webhookCallback(bot, ...) с веб-сервером, замените его на bot.start(): у этих тарифов пока нет публичного HTTPS-адреса для вебхука.
Хватит ли bot.start() для загруженного бота?
Для большинства ботов да. bot.start() обрабатывает сообщения одно за другим; в документации grammY сказано, что этого хватает примерно на 5.000 сообщений в час, а для большего объёма или для долгих команд, например передачи больших файлов, рекомендуется пакет @grammyjs/runner. Runner тоже использует long polling, поэтому он работает на наших тарифах.
Можно ли запустить grammY на Bun или Deno вместо Node.js?
Да. При заказе выберите Bun или Deno вместо Node.js: на нашей странице хостинга Telegram-ботов grammY указан для обоих. Шаги на этой странице относятся к Node.js.
Готовы запустить бота на grammY круглосуточно? Посмотрите тарифы на странице хостинга Telegram-ботов.



