Перейти к содержанию

Как настроить webhook Telegram-бота на localhost

Запустите обработчик Telegram Bot API на своём компьютере и направьте к нему обновления по публичному HTTPS-адресу. На тестовом боте вы проверите весь путь от сообщения в Telegram до ответа локального сервера.

Пошаговая настройка

  1. Запустите локальный обработчик обновлений

    Создайте отдельного тестового бота через @BotFather и сохраните его токен для третьего шага. В первом терминале Bash выполните пример с Python 3 и OpenSSL. Пример слушает только 127.0.0.1:3000, проверяет секретный заголовок и выводит номер обновления. Он подтверждает получение события и не отправляет сообщения в чат. Сохраните показанный секрет для регистрации webhook и держите его отдельно от токена бота.

    export TELEGRAM_WEBHOOK_SECRET="$(openssl rand -hex 24)"
    printf 'Webhook secret: %s\n' "$TELEGRAM_WEBHOOK_SECRET"
    python3 -u - <<'PY'
    import hmac
    import json
    import os
    from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
    
    secret = os.environ["TELEGRAM_WEBHOOK_SECRET"].encode()
    
    class Handler(BaseHTTPRequestHandler):
        def do_POST(self):
            if self.path != "/telegram":
                self.send_error(404)
                return
            supplied = self.headers.get("X-Telegram-Bot-Api-Secret-Token", "")
            if not hmac.compare_digest(supplied.encode(), secret):
                self.send_error(403)
                return
            try:
                size = int(self.headers.get("Content-Length", "0"))
                if not 0 < size <= 1_048_576:
                    self.send_error(413)
                    return
                update_id = json.loads(self.rfile.read(size))["update_id"]
                if type(update_id) is not int:
                    raise ValueError("Invalid update ID")
            except (ValueError, KeyError, TypeError):
                self.send_error(400)
                return
            print(f"Received update_id={update_id}")
            self.send_response(200)
            self.end_headers()
    
    if not secret:
        raise SystemExit("Could not generate the webhook secret")
    ThreadingHTTPServer(("127.0.0.1", 3000), Handler).serve_forever()
    PY
  2. Откройте HTTPS-туннель к порту обработчика

    Установите клиент ForTunnels и привяжите его к аккаунту CLI-токеном из настроек дашборда, чтобы видеть запросы в своём инспекторе. Во втором терминале запустите туннель. Скопируйте выданный HTTPS-адрес и оставьте оба процесса работать. Локальный обработчик продолжает слушать по HTTP. Telegram обращается к публичному HTTPS-входу.

    fortunnels http 3000
  3. Укажите публичный адрес в setWebhook

    В третьем терминале Bash запустите команды. При запросе введите токен тестового бота, затем секрет, который показал первый терминал, и адрес из вывода ForTunnels без завершающего слэша. Команда добавит путь /telegram. Telegram должен вернуть JSON с ok и result, равными true. Используйте отдельного бота: setWebhook изменяет адрес доставки для этого токена, а активный webhook несовместим с получением обновлений через getUpdates.

    read -rsp 'BotFather token: ' BOT_TOKEN
    printf '\n'
    read -rsp 'Webhook secret: ' TELEGRAM_WEBHOOK_SECRET
    printf '\n'
    read -rp 'Public HTTPS URL: ' TUNNEL_URL
    curl -fsS --config - <<CURL
    url = "https://api.telegram.org/bot$BOT_TOKEN/setWebhook"
    data-urlencode = "url=$TUNNEL_URL/telegram"
    data-urlencode = "secret_token=$TELEGRAM_WEBHOOK_SECRET"
    data-urlencode = "allowed_updates=[\"message\"]"
    CURL
  4. Отправьте сообщение и проверьте доставку

    Откройте чат с тестовым ботом и отправьте ему сообщение, например «Проверка webhook». В дашборде откройте туннель и его инспектор. Найдите свежую строку POST /telegram и проверьте код 200. В первом терминале появится Received update_id с номером события. Если сообщений нет, команда getWebhookInfo покажет сохранённый адрес, число ожидающих обновлений и последнюю ошибку, если она была.

    curl -fsS --config - <<CURL
    url = "https://api.telegram.org/bot$BOT_TOKEN/getWebhookInfo"
    CURL
  5. Снимите webhook перед остановкой туннеля

    Удалите webhook у тестового бота, пока публичный адрес ещё активен. Команда очищает переменные третьего терминала после успешного ответа. Она не сбрасывает очередь ожидающих обновлений. Затем остановите туннель и обработчик клавишами Ctrl+C. Если продолжите работу в режиме опроса, запускайте его после удаления webhook.

    curl -fsS --config - <<CURL && unset BOT_TOKEN TELEGRAM_WEBHOOK_SECRET TUNNEL_URL
    url = "https://api.telegram.org/bot$BOT_TOKEN/deleteWebhook"
    request = "POST"
    CURL
Пример результата после тестового сообщения
Инспектор: POST /telegram → 200
Локальный терминал: Received update_id=123456789

Что проверить по коду ответа

404 означает, что запрос попал не на тот путь или адрес. Сравните поле url в getWebhookInfo и строку в инспекторе. Сохраните полный HTTPS-адрес, который выдал клиент, и добавьте ровно один /telegram. Если туннель получил новый адрес после запуска, заново вызовите setWebhook и отправьте новое сообщение.

403 от обработчика означает несовпадение секрета. Проверьте, что secret_token при регистрации совпадает со значением, с которым запустили Python. При перезапуске примера OpenSSL создаёт новый секрет. Если инспектор не показывает тела, для этой проверки достаточно пути, кода ответа и локального журнала. Включать полный захват сообщений и секретных заголовков для пробы не требуется.

Если инспектор показывает 502, убедитесь, что первый терминал открыт и Python слушает порт 3000. Если в инспекторе вообще нет нового события, сначала сверьте URL в Telegram и состояние туннеля. Поле last_error_message может относиться к предыдущей попытке, поэтому сопоставьте время ошибки со временем отправки.

Перенесите проверку в своего бота

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

Разделите три секрета по назначению. Токен BotFather разрешает вызовы Bot API, секрет webhook проверяет входящие обновления, а токен ForTunnels привязывает CLI к вашему аккаунту. Для проверки доставки держите каждый секрет в своём процессе и не вставляйте их в задачи, скриншоты или общий журнал приложения.

Частые вопросы

Почему бот молчит, хотя в инспекторе появился код 200?

Код 200 подтверждает доставку обновления. Пример лишь печатает его идентификатор. Ответ в чате появится, когда обработчик вызовет метод sendMessage с идентификатором нужного чата.

Нужен ли Python, если бот написан на Node.js или Go?

Python нужен только для пробного обработчика. Запустите свой сервер, укажите его порт в команде туннеля, а путь реального POST-обработчика зарегистрируйте через setWebhook.

Источники

Запустите свой туннель

Зарегистрируйтесь, чтобы управлять маршрутами из дашборда.