Чтобы подключить OpenClaw к Telegram, создайте бота в @BotFather, положите его токен в ~/.openclaw/.env, добавьте блок channels.telegram в ~/.openclaw/openclaw.json и привяжите бота к своему числовому Telegram user id через allowFrom. Шлюз по умолчанию использует long polling, поэтому серверу не нужны ни публичный порт, ни домен. Большинство сбоев сводится к трём вещам: опечатка в токене (401 от getMe), неверный id в allowFrom (код сопряжения или тишина вместо ответа) или режим приватности Telegram, который скрывает сообщения в группах.
Каждый ключ и каждая команда ниже сверены с официальной документацией OpenClaw (2026.9.x) и страницами Telegram Bot API; там, где документация молчит, мы говорим об этом прямо.
Что нужно до начала
- Работающий шлюз OpenClaw: CLI
openclawна обычном хосте или Docker-образghcr.io/openclaw/openclawс каталогом~/.openclawхоста, смонтированным в/home/node/.openclaw. Ещё не установлен? Смотрите нашу инструкцию по установке. - Уже настроенный ключ LLM-провайдера (OpenAI, Anthropic, OpenAI-совместимый шлюз или Ollama).
- Аккаунт Telegram. Документация советует начинать именно с Telegram: ему "нужен только токен бота, никакой плагин устанавливать не надо".
Шаг 1: создайте бота в BotFather
Откройте Telegram, начните чат с @BotFather и отправьте /newbot. Он спросит отображаемое имя и username, оканчивающийся на bot, а затем ответит токеном вида 4839574812:AAFD39kkdpWt3ywyRZergyOLMaJhac60qc. Учебник Telegram говорит прямо: обращайтесь с ним как с паролем и никому не показывайте.
Для приватного бота с одним владельцем оставьте /setprivacy и /setjoingroups со значениями по умолчанию; к режиму приватности мы вернёмся ниже.
Шаг 2: храните токен в .env, а не в файле конфигурации
OpenClaw читает переменные окружения из родительского процесса и из ~/.openclaw/.env как глобального запасного источника, который никогда не перекрывает переменную, уже заданную в оболочке. Положите токен туда:
TELEGRAM_BOT_TOKEN=4839574812:AAFD39kkdpWt3ywyRZergyOLMaJhac60qc
Работают оба документированных способа передать его каналу:
- Запасной вариант из окружения. Если
channels.telegram.botTokenотсутствует, шлюз берётTELEGRAM_BOT_TOKEN(только для аккаунта по умолчанию; именованным аккаунтам нуженbotTokenилиtokenFile). - Явная ссылка. Запишите
"botToken": "${TELEGRAM_BOT_TOKEN}". Подстановка работает в любой строке конфигурации, раскрываются только имена в верхнем регистре, а отсутствующие переменные "остаются видимо неразрешёнными" и выдают предупреждение. Мы предпочитаем эту форму: конфигурация показывает, где хранится секрет.
Приоритет, цитата со страницы настройки: "tokenFile сильнее botToken, а botToken сильнее окружения." Поэтому, если новый токен не применяется, ищите устаревший botToken или tokenFile. tokenFile должен быть обычным файлом; символические ссылки отклоняются.
Шаг 3: блок channels.telegram в openclaw.json
Документация описывает ~/.openclaw/openclaw.json как JSON5 (комментарии и завершающие запятые допустимы); мы держим свой файл в строгом JSON. Минимальный первый блок:
{
"channels": {
"telegram": {
"enabled": true,
"botToken": "${TELEGRAM_BOT_TOKEN}",
"dmPolicy": "pairing"
}
}
}
Сокращение CLI openclaw channels add --channel telegram --token <bot-token> записывает токен прямо в файл конфигурации; на серверах мы предпочитаем ссылку на окружение, описанную выше.
dmPolicy решает, кто может писать боту в личном чате. Четыре документированных значения:
pairing(по умолчанию): незнакомый отправитель вместо ответа получает 8-символьный код, и ничего не обрабатывается, пока вы не одобрите его из CLI. Коды истекают через час, не больше трёх ожидающих на аккаунт канала.allowlist: обслуживаются только id изallowFrom, без сопряжения. Нужен хотя бы один id.open: требует, чтобыallowFromсодержал"*". Документация: использовать "только для намеренно публичных ботов с жёстко ограниченными инструментами".disabled: личные сообщения отключены.
Шлюз следит за файлом конфигурации и применяет большинство изменений автоматически (страница горячей перезагрузки в документации перечисляет, что по-прежнему требует перезапуска); в Docker docker compose up -d openclaw-gateway пересоздаёт контейнер.
Шаг 4: узнайте свой Telegram user id и задайте allowFrom
Именно здесь чаще всего что-то идёт не так. allowFrom принимает числовые Telegram user id в кавычках, как строки: "не номер телефона, не username, не ID чата или группы и не ID бота". Префиксы telegram: и tg: принимаются и нормализуются.
Три документированных способа узнать свой id:
- Запустите шлюз с политикой
pairingпо умолчанию, напишите боту и прочитайтеYour Telegram user idв его ответе о сопряжении. - Запустите
openclaw logs --followи прочитайтеsenderUserIdв записиtelegram pairing request. - Когда бот уже отвечает вам, отправьте
/whoami@<bot_username>; он подтвердит ваш user id, а в разрешённой группе ещё и id группы.
Теперь привяжите бота к себе. Пример из документации для одного владельца сохраняет pairing и добавляет allowFrom: вы одобрены заранее, посторонние видят лишь код, который можно игнорировать.
{
"channels": {
"telegram": {
"enabled": true,
"botToken": "${TELEGRAM_BOT_TOKEN}",
"dmPolicy": "pairing",
"allowFrom": ["123456789"]
}
}
}
Если запросы сопряжения не нужны вовсе, поставьте dmPolicy в allowlist с тем же allowFrom.
Шаг 5: запустите, проверьте и отправьте первое сообщение
openclaw gateway start
openclaw channels status --probe
openclaw logs --follow
channels status --probe подтверждает у Telegram, что канал готов, поэтому неверный токен проявится здесь первым. В Docker используйте обёртку со страницы установки docker compose exec openclaw-gateway sh -lc 'node dist/index.js gateway health', заменив подкоманду на channels status --probe.
Напишите боту. Если вы оставили pairing без allowFrom, получите код; одобрите его так:
openclaw pairing list telegram
openclaw pairing approve telegram <CODE>
Одобренные отправители хранятся в ~/.openclaw/state/openclaw.sqlite и переживают перезапуски. Одобрение "даёт доступ только к личным сообщениям", но не к группам. Чтобы проверить токен без OpenClaw, вызовите getMe: curl -s "https://api.telegram.org/bot<TOKEN>/getMe" на сервере, а не в браузере, чтобы токен не остался в истории.
Личный чат против групп и режим приватности
Документация считает группы поддерживаемыми при условии срабатывания по упоминанию, но для ассистента с одним владельцем личный чат безопаснее: сообщение любого другого участника является недоверенным содержимым, которое читает модель, тот самый случай prompt injection из документации. Если группа всё же нужна, должны сойтись три вещи.
1. Группа должна быть в списке разрешённых. groupPolicy по умолчанию равен allowlist, поэтому id чата должен присутствовать в channels.telegram.groups (или должен стоять подстановочный знак "*"). Id супергрупп отрицательные и начинаются с -100; прочитайте его в openclaw logs --follow, через бота, показывающего id пересланных сообщений, или через getUpdates.
2. Решите, кто может его запускать. groupAllowFrom принимает числовые user id по тем же правилам, что и allowFrom; если он не задан, используется allowFrom. Укажите там только свой id.
3. Упоминания и режим приватности. При requireMention: true бот отвечает только на упоминание, и именно этот режим страница настройки сочетает с режимом приватности Telegram (включён по умолчанию), в котором бот получает только адресованные ему команды, ответы на свои сообщения и служебные сообщения. Для requireMention: false, или если упоминания до бота не доходят, отключите режим приватности через /setprivacy в BotFather, затем удалите бота из группы и добавьте заново; Telegram применяет изменение только при повторном входе. Администраторы группы получают все сообщения в любом случае.
{
"channels": {
"telegram": {
"enabled": true,
"botToken": "${TELEGRAM_BOT_TOKEN}",
"dmPolicy": "allowlist",
"allowFrom": ["123456789"],
"groupPolicy": "allowlist",
"groupAllowFrom": ["123456789"],
"groups": {
"-1001234567890": { "requireMention": true }
}
}
}
}
Polling или webhook
"Long polling используется по умолчанию." Шлюз в цикле вызывает getUpdates Telegram, и ему нужен только исходящий HTTPS: ни открытого порта, ни домена, ни сертификата. Так работаем и мы.
Режиму webhook нужны channels.telegram.webhookUrl и channels.telegram.webhookSecret; слушатель по умолчанию использует webhookHost 127.0.0.1, webhookPort 8787 и webhookPath /telegram-webhook (/healthz зарезервирован). Он привязан к loopback, поэтому перед ним ставят обратный прокси с настоящим сертификатом (или задают webhookCertPath для самоподписанного сертификата на голом IP); Telegram доставляет только на HTTPS-порты 443, 80, 88 или 8443.
Одно правило Bot API кусает тех, кто переключается туда и обратно: getUpdates и webhook взаимоисключающие. OpenClaw вызывает deleteWebhook при старте polling; если вызов не удался из-за кратковременной сетевой ошибки, оставшийся webhook проявляется как конфликт getUpdates, и шлюз пересобирает транспорт и повторяет попытку. Только если это повторяется снова и снова, вызывайте deleteWebhook сами.
Типичные ошибки и что они значат
| Симптом | Вероятная причина | Решение |
|---|---|---|
В логах запуска getMe returned 401 | Опечатка в токене или он отозван, либо устаревший botToken/tokenFile перекрывает .env | Сгенерируйте токен заново в BotFather, обновите botToken или TELEGRAM_BOT_TOKEN, снова запустите channels status --probe |
| Бот онлайн, но никогда не отвечает на ваше личное сообщение | Ожидает запрос сопряжения, или в allowFrom записан username, номер телефона, id группы или id самого бота | openclaw pairing list telegram; прочитайте senderUserId в логах; исправьте allowFrom; openclaw doctor --fix для устаревших записей |
| Команды работают частично | Отправитель не авторизован, или setMyCommands failed с BOT_COMMANDS_TOO_MUCH | Авторизуйте отправителя; сократите число пользовательских команд или отключите нативные меню |
| Бот игнорирует сообщения в группе без упоминания | Режим приватности Telegram включён, а requireMention равен false | /setprivacy Disable в BotFather, затем удалите и заново добавьте бота |
| Бот ничего не видит в группе | Группа не указана в channels.telegram.groups, нет записи "*", или бот не участник | Добавьте id вида -100...; channels status --probe проверяет членство; логи показывают причину пропуска |
Polling stall detected | 120 секунд нет ни одного завершённого цикла long polling; часто IPv6 DNS или нестабильный исходящий канал | Перезапускается сам; если повторяется, проверьте dig +short api.telegram.org AAAA, принудительно включите IPv4 (channels.telegram.network.autoSelectFamily: false или NODE_OPTIONS=--dns-result-order=ipv4first) или задайте channels.telegram.proxy |
Текст работает, вложения падают с getaddrinfo EAI_AGAIN или ENOTFOUND | Загрузка медиа по-прежнему использует локальный DNS даже при заданных переменных окружения прокси | Задайте channels.telegram.proxy (HTTP(S) или SOCKS5), чтобы он разрешал имена хостов медиа |
Безопасность: один владелец, один токен, замена при утечке
OpenClaw по своей природе является удалённым выполнением кода: кто может написать боту, тот может управлять его инструментами. Страница безопасности требует "одну границу доверия на шлюз: один оператор или команда, участники которой доверяют друг другу", а страница о prompt injection ограничивает инструменты высокого риска (exec, browser, web_fetch, web_search) доверенными агентами или явными списками разрешённых. На практике:
- Ровно один id в
allowFrom, ваш. Никаких"*", никакого общего бота с включённымexec. - Ограничьте инструменты для всех, кроме себя. Пример из документации запрещает write и edit для подстановочного отправителя и оставляет владельца без ограничений:
"direct": { "*": { "tools": { "deny": ["write", "edit"] } }, "123456789": { "tools": {} } } - Никогда не вставляйте токен в чат, тикет или скриншот. Если он утёк,
/tokenв BotFather выдаёт замену; обновите.envи снова запуститеchannels status --probe. - Держите шлюз на loopback. Панель управления по умолчанию слушает
http://127.0.0.1:18789/; заходите на неё через SSH-туннель или Tailscale, но никогда через опубликованный порт. Telegram она не нужна, а CVE-2026-25253 (RCE в один клик через кражу токена) объясняет, почему мы на этом настаиваем. - Запускайте
openclaw security auditпосле каждого изменения конфигурации; документация называет это единственной командой, которая скажет, отклонились ли вы от безопасной настройки.
Запуск на сервере
Telegram-ассистент должен быть онлайн в момент, когда вы ему пишете, поэтому ноутбук не подходит; хватит любой небольшой Linux VM с исходящим HTTPS. Наш каталог VPS покрывает этот диапазон; если хотите пропустить установку, готовый сервер OpenClaw от 9.35 EUR в месяц поставляется с Ubuntu 24.04 и шлюзом, уже работающим в Docker: добавьте свой ключ LLM, подключите бота, как описано выше, и агент будет отвечать только вам. Выбираете между облачной моделью и собственной? Смотрите это сравнение.
Вопросы
Нужен ли домен или открытый порт для Telegram-бота?
Нет. Long polling используется по умолчанию и работает только через исходящий HTTPS. Домен, сертификат и входящий порт нужны лишь при переходе в режим webhook.
Почему бот отвечает кодом вместо ответа?
Так работает политика pairing по умолчанию: ваш id ещё не одобрен. Выполните openclaw pairing approve telegram <CODE> или добавьте свой числовой user id в allowFrom. Коды истекают через час.
Можно ли указать в allowFrom мой @username?
Нет. allowFrom и groupAllowFrom принимают только числовые Telegram user id. Старые конфигурации с записями @username преобразует openclaw doctor --fix.
Бот в моей группе, но ничего не читает. Почему?
Действуют два фильтра: id группы должен быть указан в channels.telegram.groups (или должна быть запись "*"), а режим приватности Telegram должен позволять боту видеть сообщения. Оставьте requireMention: true, либо отключите режим приватности через /setprivacy и добавьте бота заново, либо сделайте бота администратором группы.