Ngrok и Telegram Webhook на localhost
В данной заметке опишу особенности настройки и тестирования вебхука от Telegram через localhost. Но прежде чем приступим, нам важно понять следующие две проблемы:
- Telegram не может отправлять запросы на localhost (бот работает только с публичными URL)
- Telegram требует HTTPS соединение (чтобы вебхук был защищенным)
Есть несколько вариантов решения. Выделю два более удобных на мой взгляд:
- Использовать Ngrok
- Настроить свой VPS и пробросить SSH порты на localhost
Ngrok в моем случае стал приоритетом, так как сервис сам создает публичный HTTPS-адрес который перенаправляет запросы на локальный сервер. Ниже опишу основные моменты которые стали полезны.
Установка и настройка Ngrok
Варианты установки можно найти на сайте Docs: Getting Started.
Мои примеры для Debian Linux.
Прежде всего нужно зарегистрироваться в сервисе ngrok.com.
Устанавливаем Ngrok.
curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \ | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null \ && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" \ | sudo tee /etc/apt/sources.list.d/ngrok.list \ && sudo apt update \ && sudo apt install ngrok
Проверяем версию.
Важно знать, т.к. от версии зависит структура
ymlконфига.
$ ngrok -v ngrok version 3.22.0
Добавляем в конфиг authtoken.
authtokenдоступен в админке в разделе Getting Started: Your Authtoken.
Конфиг ngrok по умолчанию создается тут/home/your_name/.config/ngrok/ngrok.yml, но можно разместить и в другом месте.
$ ngrok config add-authtoken $YOUR_AUTHTOKEN
Запускаем ngrok для проверки.
$ ngrok http http://localhost:80
ngrok (Ctrl+C to quit)
Session Status online
Account your_name@gmail.com (Plan: Free)
Version 3.22.0
Region Europe (eu)
Latency 73ms
Web Interface http://127.0.0.1:4040
Forwarding https://e20b-188-114-192-46.ngrok-free.app -> http://localhost:80
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
На базовом уровне этого достаточно чтобы начать тестировать. Но в моем случае понадобилось решить еще несколько проблем:
- Настроить тестовый статический домен на стороне ngrok (по умолчанию создается динамический)
- Настроить домен для localhost (прописан в файле hosts для проекта)
- Настроить заголовок для Xdebug
Пример моего конфига:
version: "3"
agent:
authtoken: your-authtoken
tunnels:
tg_webhook:
domain: tg-webhook-expert-test.ngrok-free.app
addr: tg-webhook.local:80
proto: http
host_header: "tg-webhook.local"
inspect: false
traffic_policy:
inbound:
- actions:
- type: "add-headers"
config:
headers:
cookie: "XDEBUG_SESSION=start"
Важно! Директивы конфига могут отличаться в зависимости от версии. В любом случае советую пользоваться разделом Docs.
domain нужен для настройки статического домена, которые предварительно создается в админке в разделе Universal Gateway: Domains, иначе ngrok при каждом запуске формирует динамический домен который придется постоянно обновлять в Telegram (пример будет ниже).
addr,proto,host_header,inspect нужно для перенаправления на статический домен в файле hosts.
traffic_policy и все что внутри, нужно для проброса заголовка с кукой для Xdebug.
Создание Telegram Bot
Telegram Bot который будет реагировать на сообщения в чате и пересылать их в наш сервис. Детально расписывать этот процесс не буду, т.к. в сети есть гайды на эту тему. Я начал с этих мест:
После создания бота мы получим token типа 110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw, который будем использовать для настройки нашего webhook.
Установливаем webhook.
$ curl -X POST "https://api.telegram.org/bot110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw/setWebhook" \
-H "Content-Type: application/json" \
-d '{
"url": "https://tg-webhook-expert-test.ngrok-free.app/v1/telegram/webhook/",
"max_connections": 40,
"allowed_updates": ["message", "callback_query"]
}'
{
"ok":true,
"result":true,
"description":"Webhook is already set"
}
И проверяем настройки.
$ curl "https://api.telegram.org/bot110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw/getWebhookInfo"
{
"ok":true,
"result":{
"url":"https://tg-webhook-expert-test.ngrok-free.app/v1/telegram/webhook",
"has_custom_certificate":false,
"pending_update_count":0,
"max_connections":40,
"ip_address":"18.192.31.165",
"allowed_updates":[
"message",
"callback_query"
]
}
}
Тестирование на localhost
Запускаем ngrok.
ngrok start tg_webhook
ngrok (Ctrl+C to quit)
Session Status online
Account your_name@gmail.com (Plan: Free)
Version 3.22.0
Region Europe (eu)
Latency 73ms
Web Interface http://127.0.0.1:4040
Forwarding https://tg-webhook-expert-test.ngrok-free.app -> http://tg-webhook.local:80
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
Проверяем webhook локально.
$ curl -X POST "http://tg-webhook.local/v1/telegram/webhook" -d '{"test":true}'
{"test":true}
Проверяем webhook через ngrok.
$ curl -X POST "https://tg-webhook-expert-test.ngrok-free.app/v1/telegram/webhook" -d '{"test":true}'
{"test":true}
Пишем сообщение в чате Telegram и Bot должен переслать его в наш сервис. Запрос будет примерно таким:
POST /v1/telegram/webhook HTTP/1.1
Content-Length: 409
X-Forwarded-Host: tg-webhook-expert-test.ngrok-free.app
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/json
Cookie: XDEBUG_SESSION=start
Host: tg-webhook.local
X-Forwarded-For: 91.108.5.110
X-Forwarded-Proto: https
{
"update_id": 281145287,
"message": {
"message_id": 25,
"from": {
"id": 1624941878,
"is_bot": false,
"first_name": "Your",
"last_name": "Username",
"username": "your_username",
"language_code": "en"
},
"chat": {
"id": 1624941878,
"first_name": "Your",
"last_name": "Username",
"username": "your_username",
"type": "private"
},
"date": 1744737539,
"text": "Test Message"
}
}