Telegram bot Webhook как настроить и запустить

Я тогда давно написал статью про создание Telegram бота, и обещал дополнить её описанием настройки работы через webhook, но так и не дополнил. Вот только сейчас дошли руки.

This article in english 🇺🇸.

Как пишут в документации, общаться с серверами Telegram бот может двумя способами:

  1. getUpdates — pull: ваш бот постоянно дёргает сервер Telegram и проверяет есть ли новые сообщения;
  2. setWebhook — push: по мере поступления новых сообщений сервер Telegram отправляет их вашему боту.

Разницу можно изобразить следующим образом:

Очевидно, что второй способ (setWebhook
) рациональнее для всех участников процесса. Однако в нём присутствует неявная сложность: кто-то должен принимать сообщения от Telegram на стороне бота, то есть необходим веб-сервер или его эквивалент.

Что нужно сделать:

  1. Заиметь доменное имя для сервера и получить на него сертификат (например, от Let’s Encrypt). Документация также говорит, что в случае самоподписанного сертификата можно обойтись и просто IP адресом, но этого я не пробовал;
  2. Запилить серверную часть на стороне бота (куда будет ломиться Telegram);
  3. Зарегистрировать адрес серверной части в Telegram (зацепить webhook на endpoint), чтобы Telegram знал, куда ломиться с сообщениями.

Сертификат

С доменом и сертификатом просто. Домен у меня уже был, а сертификат я получил по этой инструкции.

Вариант с самоподписанным сертификатом на прямой IP адрес я оставляю вам на самостоятельное изучение.

Серверная часть

Серверная часть чуть посложнее. Я переделал текущую реализацию бота на pyTelegramBotAPI, используя пример для AIOHTTP.

Ставим необходимые пакеты:

pip install pyTelegramBotAPI pip install aiohttp pip install cchardet pip install aiodns

И сокращённо код бота теперь такой:

import
 config import
 telebot from
 aiohttp import
 web import
 ssl  WEBHOOK_LISTEN =
 "0.0.0.0"
 WEBHOOK_PORT =
 8443
  WEBHOOK_SSL_CERT =
 "/etc/letsencrypt/live/YOUR.DOMAIN/fullchain.pem"
 WEBHOOK_SSL_PRIV =
 "/etc/letsencrypt/live/YOUR.DOMAIN/privkey.pem"
  API_TOKEN =
 config.
token bot =
 telebot.
TeleBot(API_TOKEN)  app =
 web.
Application()  # process only requests with correct bot token
 async def
 handle
(request):     if
 request.
match_info.
get("token"
) ==
 bot.
token:         request_body_dict =
 await request.
json()         update =
 telebot.
types.
Update.
de_json(request_body_dict)         bot.
process_new_updates([update])         return
 web.
Response()     else
:         return
 web.
Response(status=
403
)  app.
router.
add_post("/{token}/"
, handle)  help_string =
 [] help_string.
append("*Some bot* - just a bot.
nn
"
) help_string.
append("/start - greetings
n
"
) help_string.
append("/help - shows this help"
)  # - - - messages
  @bot.message_handler
(commands=
["start"
]) def
 send_welcome
(message):     bot.
send_message(message.
chat.
id, "Ololo, I am a bot"
)  @bot.message_handler
(commands=
["help"
]) def
 send_help
(message):     bot.
send_message(message.
chat.
id, ""
.
join(help_string), parse_mode=
"Markdown"
)  # - - -
  context =
 ssl.
SSLContext(ssl.
PROTOCOL_TLSv1_2) context.
load_cert_chain(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV)  # start aiohttp server (our bot)
 web.
run_app(     app,     host=
WEBHOOK_LISTEN,     port=
WEBHOOK_PORT,     ssl_context=
context, )

Что здесь происходит: мы запускаем мини-веб-сервер, который слушает порт 8443 и отвечает на запросы через определённый endpoint, который образован токеном бота. Токен используется здесь как достаточно уникальный идентификатор, чтобы какой-нибудь мимокрокодил из интернета не навызывал бота и не натворил дел. Полный адрес endpoint’а будет выглядеть вот так: https://YOUR.DOMAIN:8443/YOUR-TOKEN/
.

Обратите также внимание на отличия от стандартного примера из репозитория:

  • в качестве файла сертификата указан fullchain.pem
    , а не cert.pem
    ;
  • удалён код снятия и установки webhook’а.

Так как бота я запускаю не из-под root’а, сервис начал валиться с такой ошибкой:

python-bot[
1824
]
: Traceback (
most recent call last)
: python-bot[
1824
]
:   File "/usr/local/bin/bot/bot.py"
, line 142
, in  python-bot[
1824
]
:     context.load_cert_chain(
WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV)
 python-bot[
1824
]
: PermissionError: [
Errno 13
]
 Permission denied systemd[
1
]
: telegram-bot.service: Main process exited, code=
exited, status=
1
/FAILURE systemd[
1
]
: telegram-bot.service: Failed with result 'exit-code'
.

То есть, у пользователя, из-под которого выполняется скрипт, нет доступа к /etc/letsencrypt/
, чтобы открыть файл сертификата. Я попытался дать доступ к каталогу для новой группы, включив в неё этого пользователя:

groupadd letsencrypt usermod -a -G letsencrypt userforbot chgrp -R letsencrypt /etc/letsencrypt/

Но он один фиг не мог открыть файлы оттуда, даже простой ls
выдавал ошибку доступа. В общем, или мои познания Linux полный отстой, или одно из двух. Пришлось тупо назначить его владельцем:

chown -R userforbot:letsencrypt /etc/letsencrypt/

Тогда сервис запустился нормально.

Регистрация

Теперь осталось самое, как оказалось, сложное — зарегистрировать endpoint бота в Telegram. Сложности возникли потому что я сначала неправильно понял принцип составления endpoint’а, а также из-за проблем с проверкой сертификата.

Для установки/регистрации webhook’а нужно выполнить следующий HTTP запрос (можно просто открыть этот URL в браузере):

https:
//api.telegram.org/botYOUR-TOKEN/setWebhook?url
=
https:
//YOUR.DOMAIN:
8443
/YOUR-TOKEN/

Пока я экспериментировал и разбирался с форматом endpoint’а, Telegram возвращал мне нормальный результат:

{     "description"
: "Webhook was set"
,     "ok"
: true
,     "result"
: true
 }

Но потом я его видимо задолбал, и он стал возвращать мне следующее:

{     "ok"
: false
,     "error_code"
: 504
,     "description"
: "Gateway Timeout"
 }

Но оказалось, что это ни на что не влияет, и webhook нормально устанавливается, так что можно даже не дожидаться таймаута, а просто отменять запрос через пару секунд.

Проверить статус webhook’а можно таким запросом:

https:
//api.telegram.org/botYOUR-TOKEN/getWebhookInfo

Если всё нормально, должно вернуть такое:

{     "ok"
: true
,     "result"
: {         "url"
: "https://YOUR.DOMAIN:8443/YOUR-TOKEN/"
,         "has_custom_certificate"
: false
,         "pending_update_count"
: 0
,         "max_connections"
: 40
     } }

Как видим, в поле url
стоит наш endpoint.

Однако, мне оно сейчас возвращает такое:

{
     "ok"
: true,     "result"
: {
         "url"
: "https://YOUR.DOMAIN:8443/YOUR-TOKEN/"
,         "has_custom_certificate"
: false,         "pending_update_count"
: 0
,         "last_error_date"
: 1543762687
,         "last_error_message"
: "SSL error {error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed}"
,         "max_connections"
: 40
     }
 }

Что указывает на некие проблемы с сертификатом. При этом бот работает нормально, то есть эта ошибка ни на что не влияет. Однако, если вместо fullchain.pem
оставить cert.pem
(как было указано в примере), то бот работать перестанет.

Стоит также отметить, что если вы установили webhook, то опрос Telegram через getUpdates
работать больше будет. Чтобы снять webhook, надо отправить тот же самый запрос, что и для установки, но на этот раз без параметра url
:

https:
//api.telegram.org/botYOUR-TOKEN/setWebhook

В ответ придёт:

{     "ok"
: true
,     "result"
: true
,     "description"
: "Webhook was deleted"
 }

Ну и всё, не так уж и сложно. Если бы в документации (и сторонних манулах из интернетов) была указана такая простая вещь, что для webhook’а всего-то нужен лишь веб-сервер на стороне бота, я бы это сделал уже сто лет назад. Конечно, продвинутым чувакам это скорее всего было очевидным, но для меня нет.

Telegram Webhook – это технология, позволяющая отслеживать в чате события в реальном времени и отправлять информацию о нем на указанный адрес. Если вы создали бот, то метод необходим, чтобы система могла реагировать на сообщения и действия пользователей. Получая информацию о них, сервер отправляет ее программе бота, в алгоритм которой заложена обработка.

Что нужно для рабочего коннекта Webhook

  • Адрес (URL) страницы с программным кодом;
  • Поддержка IPv4, но рекомендуем поддержка IPv6 из-за частой блокировки телеграмма по IPv4;
  • Возможность сервера обрабатывать HTTPS трафик;
  • Наличие SSL сертификата.

Команды работы с методом описаны в Telegram Webhook Bot API. К ним относятся:

  • setWebhook – установка соединения
    . При этом необходимо передать адрес, на который будут отправляться сообщения из чата;
  • deleteWebhook – удаление соединения
    . Указание предыдущей команды без параметров также удалит его;
  • getWebhookInfo – получение текущего статуса
    соединения.

Активация Webhook Telegram

Чтобы использовать метод постоянного коннекта сервера и бота, следует запустить программный код, в котором выполняется команда API для Телеграм.

Для официального сертификата SSL
:

https://api.telegram.org/botТОКЕН/setWebhook?url=ВАШ_ДОМЕН  

Для самоподписанного сертификата
:

https://api.telegram.org/botТОКЕН/setWebhook?url=ВАШ_ДОМЕН&certificate=ФАЙЛ_СЕРТИФИКАТА  

Какая команда будет использоваться для отправки сообщения в мессенджер зависит от языка программирования.

Например, для PHP это будет curl_exec(), а для Python — requests.get().

Для установки сертификата на сервера чаще всего используется криптографический пакет с открытым исходным кодом OpenSSL
. Его можно скачать с официального сайта. Настройка зависит от операционной системы и сервера.

Официальные цифровые подписи устанавливаются на хостинге провайдером. Эта одна из услуг большинства компаний.

Прежде чем использовать Webhooks убедитесь, что вам доступен этот функционал.

Создание бота для Telegram на Webhooks предпочтительнее, чем использования метода getUpdates. Во втором случае приходится закладывать в код постоянное обращение этой команды к боту. Это делается в циклическом режиме. В конце концов начинаются баги, и он подвисает. Webhook же держит постоянное соединение, но запросы отправляются только когда произошло событие, например, пользователь ввел сообщение.

Telegram — быстро развивающийся мессенджер, множество программистов уже попробовали себя в создании ботов для telegram.

В данной статье мы разберёмся с созданием самоподписанного сертификата, научимся устанавливать этот сертификат в nginx и научим нашего бота получать обновления с помощью способа WebHook.

Методы взаимодействия с ботом:

Телеграмм разрешает устанавливать свои сертификаты https, что позволит нас не покупать дорогостоящий сертификат.

Для взаимодействия с пользователем в телеграмме используются 2 принципиально разных способа.

Существует ещё один способ получения сообщений от бота. Это использование WebHook. Идея заключается в том, что сервер сам будет присылать нам сообщения пользователя, а мы будем решать, что с ними делать. Каждый раз при получении обновления на этот адрес будет отправлен HTTPS POST с сериализованным в JSON объектом Update. В основном мы будем работать с объектом Message, который, соответственно, получим из Update.

Настройка синхронизации бота telegram с помощью setWebHook:

Приступим к настройке данного способа синхронизации. Для начала нам будет необходимо создать и настроить ssl сертификат.

Генерация и установка ssl сертификата:

Чтобы создать сертификат нам необходимо выполнить следующие действия:

Создадим папку в которую поместим наши полученные сертификаты:

Генерируем наш сертификат с помощью OpenSSL.

Обратите внимание, что вместо

Вы должны написать имя своего домена, в моём случае это

После выполнения данных действий в папке /ssl/, должны появится 2 файла: YOURPRIVATE.key и YOURPUBLIC.pem

Если всё получилось, то переходим к следующему шагу. Так как телеграмм передаёт всё по безопасному протоколу ssl мы должны настроить свой сервер, чтобы он поддерживал его. У меня установлен nginx, соответственно, мы будем работать с ним.

Конфигурация веб-сервера:

Переходим к конфигурации веб-сервера. Нам понадобится файл конфигурации nginx — nginx.conf
. У меня он находится в папке: /usr/local/etc/nginx.

Открываем файл и переходим к разделу с нашим веб сервером.

У меня он выглядит следующим образом:

Мы должны добавить несколько строк, чтобы сервер начал поддерживать https.

В итоге у нас должно получится следующие:

После выполнения всех пунктов необходимо перезапустить nginx

Отлично. На данные момент мы имеем установленный и работающий сертификат. У нас всё готово для перехода к setWebhook.

Метод setWebHook:

Для начала разберёмся, что принимает на вход метод:

Параметры Тип Описание
url String HTTPS url для отправки запросов. Чтобы удалить вебхук,

отправьте пустую строку.

certificate InputFile Загрузка публичного ключа для проверки

корневого сертификата.

Подробнее в разделе про самоподписанные сертификаты.

URL — адрес до нашего скрипта-обработчика, куда будут приходить сообщения от сервера telegram.

certificate — наш полученный файл YOURPUBLIC.pem.

Установка метода синхронизации telegram bot с помощью setWebHook:

Теперь переходим на наш веб-сервер. Для удобства создадим папку telegram и в ней файл installhandler.php

У нас должно получится следующее:

kostyakulakov.ru/telegram/installhandler.php

Для безопасности я удалил все файлы, ссылка предоставлена для ознакомления с расположением файла инициализации обработчика.

Теперь вставим в наш файл следующий php код, который позволит зарегистрировать ссылку обработчика с помощью метода setWebhook

Не забудьте установить токен и путь до обработчика.

Для начала мы устанавливаем токен и путь до вашего публичного ключа сертификата.

Потом в функции regHandler, мы формируем POST-запрос с сылкой на обработчик и прикреплённым ключом. Отправляем. Выводим результат.

Если всё прошло хорошо, то вы должны получит на экран следующее:

Если всё так и прошло, то переходим к следующему шага. Если нет, то пишите в комментарии, мы обязательно разберёмся и поможем вам.

Пример обработчика пользовательских сообщений:

Теперь создадим сам обработчик пользовательских сообщений. Мы уже указывали путь в функции до него: «https://kostyakulakov.ru/telegram/handler.php»

Создадим в папке telegram файл handler.php

и наполним его следующим кодом, который будет отвечать на пользовательские сообщения:

На каждое сообщение пользователя, она будет отвечать следующим образом: «{Имя пользователя}, я получила ваше сообщение!».

Выглядит это так:

Дальше играет роль только ваша фантазия, можете обрабатывать сообщения и отвечать на них. Вы свободны в ваших действиях.

В конечном итоге мы смогли синхронизировать нашего бота с сервером, теперь мы можем обрабатывать сообщения от пользователя Telegram с помощью Web Hook.

Спасибо за внимание.

Рейтинг автора
5
Подборку подготовил
Андрей Ульянов
Наш эксперт
Написано статей
168
Ссылка на основную публикацию
Похожие публикации