Реализация Telegram-бота на Python и JavaScript с развертыванием на AWS
Развёртывание нового Telegram-бота в AWS
Вот мои заметки с пошаговым руководством по реализации и развертыванию в AWS Telegram-бота. Я добавил быстрый старт (long polling) и производственный путь (webhooks), с примерами на Python и Node.js.
Telegram-боты — это приложения, которые работают на ваших серверах и общаются с пользователями через Telegram. Мы зарегистрируем бота, напишем небольшую программу и подключим её к Telegram Bot API.
TL;DR
- Создайте бота через @BotFather → получите токен.
- Создайте небольшое приложение с python-telegram-bot или Telegraf.
- Начните с long polling локально; переключитесь на webhooks для продакшена.
Что вам понадобится
-
Аккаунт Telegram (мобильный или настольный)
-
Базовый терминал + редактор кода
-
Один из:
- Python 3.10+ и
pip
- Node.js 18+ и
npm
/pnpm
/yarn
- Python 3.10+ и
Создайте своего бота с помощью BotFather (получите токен)
- В Telegram найдите @BotFather и начните чат.
- Отправьте
/newbot
и следуйте инструкциям, чтобы назвать своего бота и выбрать уникальное имя пользователя (должно заканчиваться наbot
), например,example_helper_bot
. - BotFather отвечает с API токеном вроде
123456:ABC-DEF...
. Обращайтесь с ним как с паролем; не добавляйте его в Git. Вы всегда можете сгенерировать его заново через BotFather, если он утерян.
Совет: Официальное руководство Telegram подробно описывает эти шаги и как проверить ваш токен с помощью
getMe
.
Выберите свою платформу
Вы можете вызывать сырой HTTP Bot API самостоятельно, но использование поддерживаемой библиотеки ускорит процесс.
- Python:
python-telegram-bot
(асинхронный, современный). ([https://docs.python-telegram-bot.org]) - Node.js:
telegraf
(зрелый, дружелюбный к TypeScript). ([https://telegraf.js.org])
Сам Bot API документирован здесь и является источником истины для методов вроде getUpdates
и setWebhook
.
Быстрый старт: запуск локально с long polling
Long polling идеален для локальной разработки: ваш бот многократно запрашивает у Telegram новые обновления через getUpdates
. (В продакшене вы, скорее всего, переключитесь на webhooks.)
Telegram поддерживает два взаимоисключающих способа получения обновлений:
getUpdates
(polling) или webhooks; обновления хранятся до 24 часов.
Вариант A: Python (с python-telegram-bot
)
Установка и создание шаблона
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install python-telegram-bot
Код: bot.py
import os
from telegram import Update
from telegram.ext import ApplicationBuilder, CommandHandler, MessageHandler, ContextTypes, filters
TOKEN = os.environ["TELEGRAM_BOT_TOKEN"] # export TELEGRAM_BOT_TOKEN=123:ABC
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("👋 Привет! Отправьте мне что-нибудь, и я повторю это.")
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(update.message.text)
def main():
app = ApplicationBuilder().token(TOKEN).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(MessageHandler(filters.TEXT & filters.COMMAND, echo))
app.run_polling() # long polling
if __name__ == "__main__":
main()
Запустите его:
export TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
python bot.py
Это использует ApplicationBuilder
из текущей стабильной документации.
Вариант B: Node.js (с telegraf
)
Установка и создание шаблона
npm init -y
npm i telegraf
Код: index.js
const { Telegraf } = require('telegraf');
const bot = new Telegraf(process.env.BOT_TOKEN); // установите переменную окружения BOT_TOKEN
bot.start((ctx) => ctx.reply('👋 Привет! Отправьте мне что-нибудь, и я повторю это.'));
bot.on('text', (ctx) => ctx.reply(ctx.message.text));
bot.launch();
// корректное завершение
process.once('SIGINT', () => bot.stop('SIGINT'));
process.once('SIGTERM', () => bot.stop('SIGTERM'));
Запустите его:
export BOT_TOKEN=123456:ABC-DEF...
node index.js
Это отражает официальный пример Telegraf «Getting started».
Сделайте его полезным (команды и кнопки)
Добавьте команду /help
Python
from telegram.ext import CommandHandler
async def help_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("/start – приветствие\n/help – эта помощь")
app.add_handler(CommandHandler("help", help_cmd))
CommandHandler
— стандартный способ привязки /команд
.
Node (Telegraf)
bot.help((ctx) => ctx.reply('/start – приветствие\n/help – эта помощь'));
Быстрые кнопки ответа (пользовательская клавиатура)
Python
from telegram import ReplyKeyboardMarkup
async def start(update: Update, context):
keyboard = [["Помощь", "О боте"]]
await update.message.reply_text(
"Выберите опцию:",
reply_markup=ReplyKeyboardMarkup(keyboard, resize_keyboard=True)
)
Node (Telegraf)
const { Markup } = require('telegraf');
bot.start((ctx) => {
ctx.reply("Выберите опцию:", Markup.keyboard([["Помощь", "О боте"]]).resize());
});
Производство: переключение на webhooks
В продакшене Telegram отправляет обновления на ваш HTTPS-эндпоинт. Вы можете установить это с помощью setWebhook
, опционально предоставив секретный токен, чтобы вы могли проверить запрос через заголовок X-Telegram-Bot-Api-Secret-Token
.
Установите webhook с помощью curl
:
TOKEN=123456:ABC-DEF...
WEBHOOK_URL="https://your-domain.com/telegram/${TOKEN}" # включите секретный путь
SECRET="my-secret-42"
curl -X POST "https://api.telegram.org/bot${TOKEN}/setWebhook" \
-d url="${WEBHOOK_URL}" \
-d secret_token="${SECRET}" \
-d drop_pending_updates=true
Ключевые моменты из спецификации:
setWebhook
требует HTTPS URL и поддерживаетsecret_token
.- Пока установлен webhook, вы не можете использовать
getUpdates
. - Поддерживаемые порты включают 443, 80, 88, 8443.
Опции сервера webhook
- Node (встроенный webhook Telegraf):
bot.launch({
webhook: {
domain: "your-domain.com",
port: 8080,
// опциональный секретный заголовок
secretToken: process.env.WEBHOOK_SECRET
}
});
Telegraf предоставляет первоклассные опции webhook и интегрируется с Express/Fastify/Cloudflare Workers и т.д.
- Python (
python-telegram-bot
) PTB хорошо работает с ASGI/WSGI фреймворками (FastAPI, Starlette, Flask). ИспользуйтеApplicationBuilder().token(...).build()
, откройте POST маршрут, который подает входящие JSON обновления в ваше приложение, и вызовитеbot.set_webhook(...)
. См. документациюApplicationBuilder
для шаблонов построения. ([docs.python-telegram-bot.org][2])
Тестируете локально? Используйте туннель (например,
ngrok
), чтобы открытьhttps://...
для Telegram, затем вызовитеsetWebhook
с публичным URL.
Настройка команд бота (необязательно, но удобно для пользователей)
Вы можете определить список команд бота (что видят пользователи, когда вводят /
) либо:
- В BotFather через /mybots → Edit Bot → Edit Commands, либо
- Программно с помощью
setMyCommands
с использованием вашей библиотеки или сырого Bot API.
Официальное руководство Telegram «From BotFather to Hello World» содержит ссылки на более сложное управление командами и примеры, если вы хотите углубиться.
Рассмотрения по развертыванию
Любой хост с поддержкой HTTPS подойдет:
- Небольшая ВМ (Ubuntu + systemd)
- Serverless (AWS Lambda/Cloud Functions) с интеграцией webhook
- Контейнеры на платформах вроде Fly.io/Render/Heroku
Документация Telegraf включает примеры для Lambda, GCF, Express, Fastify и т.д.
Чек-лист безопасности и надежности
- Держите токен в секрете (переменные окружения, менеджер секретов). Отозовите в BotFather, если он утерян.
- Используйте
secret_token
с webhooks и проверяйте заголовокX-Telegram-Bot-Api-Secret-Token
. - Не смешивайте polling и webhooks; выбирайте один за раз.
- Обрабатывайте ошибки и повторные попытки: Telegram будет повторно отправлять не-2xx ответы webhook. Логируйте соответствующим образом.
- Будьте внимательны с типами обновлений (сообщения, коллбэки, инлайн-запросы, платежи и т.д.) и подписывайтесь только на то, что вам нужно (
allowed_updates
).
Работа напрямую с HTTP API (необязательно)
Вы можете вызывать эндпоинты вроде:
https://api.telegram.org/bot<token>/getMe
https://api.telegram.org/bot<token>/getUpdates
https://api.telegram.org/bot<token>/sendMessage
Используйте GET или POST с JSON или form data в соответствии со спецификацией.
Что делать и читать дальше
- Официальная справка Bot API: методы, объекты, лимиты, форматирование, платежи, инлайн-режим.
- Официальное руководство «From BotFather to ‘Hello World’»: более детальный обзор и примеры на нескольких языках.
- Документация python-telegram-bot (стабильная): современные асинхронные паттерны.
- Документация Telegraf: быстрые рецепты, помощники webhook и типы TS.
Шаги развертывания в AWS для версии на Python
У нас есть два основных варианта развертывания Telegram-бота на инфраструктуре AWS:
- A) Serverless (API Gateway + Lambda + Secrets Manager) — самый дешевый и простой в использовании, отлично подходит для умеренного трафика.
- B) Контейнеризация (ECS Fargate + ALB + ACM) — производственный уровень для стабильного трафика и долго работающих библиотек, таких как
python-telegram-bot
в режиме вебхуков.
A) Serverless на AWS (API Gateway + Lambda)
Используйте этот вариант, если хотите обойтись без серверов и минимизировать затраты на простой. Код ниже обрабатывает вебхуки Telegram напрямую (без долго работающего цикла событий).
- Подготовка минимального обработчика Lambda (Python)
Создайте handler.py
:
import json, os, urllib.request
BOT_TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
SECRET_HEADER = os.environ.get("WEBHOOK_SECRET", "") # должен совпадать с secret_token в Bot API setWebhook
API_BASE = f"https://api.telegram.org/bot{BOT_TOKEN}"
def reply(chat_id: int, text: str):
data = json.dumps({"chat_id": chat_id, "text": text}).encode()
req = urllib.request.Request(f"{API_BASE}/sendMessage", data=data, headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req) as resp:
return resp.read()
def lambda_handler(event, context):
# 1) Проверка секретного заголовка Telegram (устанавливается при настройке вебхука)
if SECRET_HEADER:
if event.get("headers", {}).get("X-Telegram-Bot-Api-Secret-Token") != SECRET_HEADER:
return {"statusCode": 401, "body": "invalid secret"}
# 2) Парсинг обновления
body = event.get("body") or "{}"
update = json.loads(body)
message = update.get("message") or update.get("edited_message")
if not message:
# игнорируем несообщения (callback_query, inline_query и т.д.) пока что
return {"statusCode": 200, "body": "ok"}
chat_id = message["chat"]["id"]
text = (message.get("text") or "").strip()
# 3) Простая маршрутизация
if text.startswith("/start"):
reply(chat_id, "👋 Привет из AWS Lambda! Отправьте любой текст, и я его отражу.")
elif text.startswith("/help"):
reply(chat_id, "/start – приветствие\n/help – помощь\n(Развернуто на AWS Lambda)")
elif text:
reply(chat_id, text) # эхо
return {"statusCode": 200, "body": "ok"}
Это использует прямые HTTPS-запросы к Bot API, чтобы сделать Lambda легкой и дружелюбной к холодным стартам. Позже можно расширить маршрутизацию.
- Упаковка и развертывание Lambda
# Структура проекта
# .
# ├─ handler.py
# └─ requirements.txt # (оставьте пустым для этого минимального примера)
zip -r function.zip handler.py
aws lambda create-function \
--function-name telegram-bot-webhook \
--runtime python3.11 \
--role arn:aws:iam::<ACCOUNT_ID>:role/<LambdaExecutionRole> \
--handler handler.lambda_handler \
--timeout 10 \
--memory-size 256 \
--zip-file fileb://function.zip \
--environment Variables='{TELEGRAM_BOT_TOKEN=<TOKEN_FROM_BOTFATHER>,WEBHOOK_SECRET=my-secret-42}'
IAM роль (<LambdaExecutionRole>
) должна иметь AWSLambdaBasicExecutionRole
для CloudWatch Logs.
Предпочтительнее хранить ваш токен в AWS Secrets Manager и загружать его при инициализации — в этом примере используются переменные окружения для краткости.
- Создание HTTPS-эндпоинта (API Gateway)
# HTTP API (не REST) для меньшей задержки
API_ID=$(aws apigatewayv2 create-api \
--name telegram-webhook \
--protocol-type HTTP \
--target arn:aws:lambda:<REGION>:<ACCOUNT_ID>:function:telegram-bot-webhook \
--query 'ApiId' --output text)
# Добавление маршрута POST /webhook по умолчанию
aws apigatewayv2 create-integration \
--api-id $API_ID \
--integration-type AWS_PROXY \
--integration-uri arn:aws:lambda:<REGION>:<ACCOUNT_ID>:function:telegram-bot-webhook \
--payload-format-version 2.0
aws apigatewayv2 create-route \
--api-id $API_ID \
--route-key "POST /webhook" \
--target "integrations/$(
aws apigatewayv2 get-integrations --api-id $API_ID --query 'Items[0].IntegrationId' --output text
)"
aws apigatewayv2 create-deployment --api-id $API_ID
GW_URL=$(aws apigatewayv2 get-apis --query "Items[?ApiId=='$API_ID'].ApiEndpoint" --output text)
echo $GW_URL # например, https://abc123.execute-api.ap-somewhere.amazonaws.com
Убедитесь, что разрешение Lambda добавлено автоматически; если нет:
aws lambda add-permission \
--function-name telegram-bot-webhook \
--statement-id apigw \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-arn "arn:aws:execute-api:<REGION>:<ACCOUNT_ID>:$API_ID/*/*/webhook"
- Настройка вебхука для Telegram
TOKEN=<TOKEN_FROM_BOTFATHER>
WEBHOOK_URL="$GW_URL/webhook"
SECRET="my-secret-42"
curl -X POST "https://api.telegram.org/bot${TOKEN}/setWebhook" \
-d url="${WEBHOOK_URL}" \
-d secret_token="${SECRET}" \
-d drop_pending_updates=true
Отправьте /start
вашему боту — сообщения будут проходить через API Gateway → Lambda.
- Логи, повторные попытки и обновления
- Просмотр логов:
aws logs tail /aws/lambda/telegram-bot-webhook --follow
- Telegram повторяет попытки, если ваш эндпоинт не возвращает 2xx; держите ответы быстрыми.
- Для развертывания нового кода: переупакуйте +
aws lambda update-function-code --function-name telegram-bot-webhook --zip-file fileb://function.zip
.
B) Контейнеризация python-telegram-bot
на ECS Fargate + ALB
Используйте этот вариант, если хотите удобство
python-telegram-bot
(PTB) с полноценным асинхронным приложением и постоянными соединениями. Мы будем запускать PTB за HTTPS-балансировщиком нагрузки.
- Код приложения (FastAPI + вебхук PTB)
app.py
:
import os, asyncio
from fastapi import FastAPI, Request, Header
from telegram import Update
from telegram.ext import ApplicationBuilder, CommandHandler, MessageHandler, ContextTypes, filters
TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
SECRET = os.environ.get("WEBHOOK_SECRET", "")
app = FastAPI()
tg_app = None # Приложение PTB
async def start_cmd(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("🚀 Привет из ECS Fargate + PTB!")
async def echo(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(update.message.text)
@app.on_event("startup")
async def on_startup():
global tg_app
tg_app = ApplicationBuilder().token(TOKEN).build()
tg_app.add_handler(CommandHandler("start", start_cmd))
tg_app.add_handler(MessageHandler(filters.TEXT & filters.COMMAND, echo))
# Нет run_polling(); мы будем подавать вебхуки вручную.
@app.post("/telegram/webhook")
async def telegram_webhook(request: Request, x_telegram_bot_api_secret_token: str | None = Header(default=None)):
if SECRET and (x_telegram_bot_api_secret_token != SECRET):
return {"ok": True} # игнорируем молча
data = await request.json()
update = Update.de_json(data, tg_app.bot)
await tg_app.process_update(update)
return {"ok": True}
Точка входа uvicorn
: uvicorn app:app --host 0.0.0.0 --port 8080
- Dockerfile
FROM python:3.11-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
RUN pip install --no-cache-dir fastapi uvicorn[standard] python-telegram-bot==21.*
COPY app.py .
EXPOSE 8080
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"]
Сборка и отправка:
aws ecr create-repository --repository-name telegram-ptb || true
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REGION=<REGION>
ECR="$ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/telegram-ptb"
aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin "$ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com"
docker build -t telegram-ptb .
docker tag telegram-ptb:latest $ECR:latest
docker push $ECR:latest
- Сервис ECS Fargate за ALB
- Создайте группу безопасности, разрешающую входящий трафик 443 на ALB; задачи ECS разрешают 8080 от группы безопасности ALB.
- Создайте приложение Application Load Balancer (ALB) с HTTPS-слушателем (443) и сертификатом ACM для вашего домена.
- Группа назначения: HTTP 8080 (тип назначения IP), путь проверки состояния
/
(FastAPI возвращает 404; можно добавить маршрут@app.get("/")
для проверки состояния).
Создайте определение задачи (Fargate) с:
- Изображением контейнера:
$ECR:latest
- Отображением портов: 8080
- Переменными окружения:
TELEGRAM_BOT_TOKEN
,WEBHOOK_SECRET
- Ролью задачи: базовая запись в CloudWatch.
Создайте сервис ECS:
- Тип запуска Fargate, желаемое количество 1+.
- Прикрепите к группе назначения ALB.
Запомните публичный HTTPS-домен ALB (или используйте Route 53 для указания DNS-имени).
- Укажите Telegram URL вебхука
TOKEN=<TOKEN_FROM_BOTFATHER>
SECRET="my-secret-42"
WEBHOOK_URL="https://your.domain.com/telegram/webhook"
curl -X POST "https://api.telegram.org/bot${TOKEN}/setWebhook" \
-d url="${WEBHOOK_URL}" \
-d secret_token="${SECRET}" \
-d drop_pending_updates=true \
-d allowed_updates='["message","edited_message","callback_query"]'
- Масштабирование и эксплуатация
- Масштабируйте задачи ECS вверх/вниз; ALB распределит трафик.
- Вращайте токены в Secrets Manager, обновляйте сервис с новыми переменными окружения задачи.
- Используйте CloudWatch Logs для логов приложения и логи доступа ALB (S3).
Какой вариант выбрать?
- Lambda + API Gateway: самый простой, самый дешевый при низком объеме; отлично подходит для ботов, которые делают несколько вызовов в минуту.
- ECS Fargate + ALB: лучший вариант, если вы хотите полный опыт
python-telegram-bot
, пользовательские middleware, фоновые задачи и стабильный трафик.
Быстрая проверка (оба подхода)
- Используйте HTTPS-эндпоинт +
secret_token
и проверяйте заголовокX-Telegram-Bot-Api-Secret-Token
. - Выберите вебхук ИЛИ опрос (не оба).
- Сохраняйте конфигурацию в Secrets Manager, а не в коде.
- Добавьте наблюдаемость: CloudWatch Logs + метрики (алармы 5xx).
- Обрабатывайте только типы обновлений, которые вам нужны; расширяйте позже.
Полезные ссылки
- Документация Python Telegram Bot
- Телеграф.js
- Руководство по созданию ботов для Telegram
- API Telegram Bots
- Обзор AWS CDK, примеры на TypeScript и Python, а также соображения о производительности
- Производительность AWS Lambda: JavaScript vs Python vs Golang
- Многослойные Lambda с AWS SAM и Python
- AWS SAM + AWS SQS + Python PowerTools
- Шпаргалка по Python
- uv - Новый менеджер пакетов, проектов и сред Python
- Установка Node.js