Документ фиксирует, что стоит унаследовать из двух выбранных репозиториев:
tdlib/telegram-bot-api, изученный коммит01a3679Olegt0rr/telegram-local, изученный коммит22c2bf5
Цель: сохранить текущую модель local-first, но сделать ее более явной, воспроизводимой и безопасной для update-очередей.
OpenClaw Gateway
-> http://127.0.0.1:8082
-> openclaw-telegram-bot-api-proxy
primary -> http://127.0.0.1:8081
Docker aiogram/telegram-bot-api:latest --local
fallback -> https://api.telegram.org
Основное правило: локальный Bot API всегда первичен. Cloud используется только как аварийный канал для безопасных запросов и не должен молча откатывать OpenClaw на старые update_id.
В официальном README local mode описан как отдельный режим, который дает большие файлы, локальные пути и upload до 2000 MB:
Что наследуем:
- запуск Bot API только с
--local/TELEGRAM_LOCAL=1; - порт
8081оставляем внутренним upstream; - в документации прокси прямо пишем, что без
--localархитектура теряет смысл; - для Docker volume обязательно сохраняем
/var/lib/telegram-bot-api.
Официальный README отдельно предупреждает: при переносе бота на локальный server нужно делать logOut на cloud, а при переносе между локальными серверами нельзя держать один token в нескольких Bot API инстансах без аккуратного перехода:
Что наследуем:
- отдельный runbook
docs/token-migration.md; - диагностическую команду/секцию для проверки текущего владельца token: local/cloud;
- запрет на автоматический
logOutиз прокси; - явную пометку cloud fallback как best-effort режима, потому что официальный server не обещает надежную доставку при одновременной жизни token на нескольких серверах.
Server хранит очередь updates в tqueue.binlog, а webhook state в webhooks_db.binlog:
Что наследуем:
- Docker volume с данными Bot API нельзя удалять или пересоздавать без runbook;
- в плане миграции обязательно проверяем, что новый контейнер использует тот же volume или корректно закрыт старый instance;
- stale local updates считаем штатным риском после переезда, а не странной случайностью;
- текущая защита proxy, которая отбрасывает local updates ниже OpenClaw offset и делает
ackчерезgetUpdates?offset=...&timeout=0, остается обязательной.
В официальной реализации:
getUpdatesконфликтует с активным webhook;- одновременно допускается только один long poll;
- отрицательный
offsetочищает часть очереди; offset <= 0стартует с головы очереди;- пустой long poll сохраняет
long_poll_offset_.
Код:
Что наследуем:
- proxy не должен создавать конкурирующий long poll без нужды;
- cloud
getUpdatesразрешен только после local failure или послеlocal-empty + cloud-pending; ack-droppedвсегда сtimeout=0;- для cloud fallback нужен отдельный cursor, потому что cloud
update_idи localupdate_idмогут разойтись; - виртуализация cloud
update_idвыше local offset остается правильной защитой от оживления старых сессий.
В официальном server:
- cloud/non-local режим ограничивает
getFileпримерно 20 MiB; - local mode возвращает absolute
file_path; - local mode принимает
file:/...как input file path; - для non-local server относительный
file_pathвыдается только для файлов в лимите.
Код:
Что наследуем:
/file/...fallback в cloud только если размер известен и не выше cloud-лимита;- неизвестный размер не fallback-ится;
- тяжелые файлы всегда остаются local-only;
LOCAL_FILE_PATH_REWRITE_FROMиLOCAL_FILE_PATH_REWRITE_TOпревращаем в документированный обязательный параметр для Docker local mode, если OpenClaw читает файл напрямую;- для upload не буферизуем multipart и не fallback-им в cloud.
Server считает активные запросы и active file uploads, а в non-local режиме применяет flood/upload ограничения:
Что наследуем:
- в proxy добавляем легкие счетчики
target=local/cloud,method,status,ms,fallback reason; - отдельно логируем active streaming uploads/downloads;
- не добавляем тяжелую metrics-систему на первом шаге, достаточно структурированных daily logs.
Пример держит aiogram/telegram-bot-api:latest отдельным service и шарит volume /var/lib/telegram-bot-api с reverse proxy:
Что наследуем:
docker-compose.example.ymlдля нашего repo;- service
telegram-bot-apiна imageaiogram/telegram-bot-api:latest; - persistent volume
telegram-bot-api-data:/var/lib/telegram-bot-api; - наружу публикуем только
127.0.0.1:8081, либо держим Bot API внутри Docker network, если proxy тоже будет контейнером; - env template с
TELEGRAM_API_ID,TELEGRAM_API_HASH,TELEGRAM_LOCAL=1.
Nginx пример дает несколько полезных настроек:
client_max_body_size 2G;- proxy timeouts по 600 секунд;
- token-safe access log;
/file/bot...умеет отдавать файлы из shared volume;- backend Bot API не светится наружу.
Код:
Что наследуем:
- token masking для логов proxy;
- большие timeout/body-size как ориентир для streaming path;
- опциональный static-file режим для
/file/...через shared volume, если понадобится разгрузить Node proxy; - backend local Bot API остается непубличным.
Что не наследуем:
- nginx как обязательный слой: наш Node proxy уже принимает решения local/cloud и понимает Telegram offsets;
- webhook-first схему для OpenClaw: OpenClaw сейчас работает через
getUpdates, а именно там нужен offset guard.
В примере aiogram bot явно использует custom API server с is_local=True:
Что наследуем:
- в README фиксируем, что OpenClaw должен смотреть не на
api.telegram.org, а на proxyhttp://127.0.0.1:8082; - proxy, а не OpenClaw, решает, когда можно уйти в cloud fallback.
Добавитьdocker-compose.example.yml.Добавить.env.exampleдля Bot API и proxy.Добавитьdocs/token-migration.md.Добавитьdocs/operations.mdс командами проверки local/cloud ownership, очереди и логов.Обновить README короткой схемой: OpenClaw -> proxy -> local Bot API -> cloud fallback.
Маскировать bot token в логах.Добавить счетчики active streaming requests.Вынести fallback-policy в именованные группы и правила:localAdminMethods:getMe,getUpdates,getWebhookInfo,deleteWebhook;safeCloudFallbackMethods: методы без тяжелых файловых тел;localOnlyMethodsи dynamic local-only причины: token/webhook ownership methods, multipart upload, тяжелый/file, неизвестный file size.
Оставить cloudgetUpdatesтолько через текущий guarded path.Явно логироватьcloud-pending-probe,virtualized-update-id,dropped-local-update,ack-dropped.
- Зафиксировать image
aiogram/telegram-bot-api:latest. - Зафиксировать volume
/var/lib/telegram-bot-api. - Решить, proxy остается systemd-сервисом или тоже уходит в compose:
- ближний путь: Bot API в Docker, proxy в user systemd;
- следующий путь: Bot API и proxy в одном compose, наружу только proxy на
127.0.0.1:8082.
- Для WSL/VM101 отдельно описать host path для
LOCAL_FILE_PATH_REWRITE_TO.
- Smoke test:
getMeчерез proxy;getUpdatesпри пустой local очереди;- маленькое фото через
getFileи/file; - файл больше cloud лимита через local only;
- local down -> cloud text command fallback.
- Stale update test:
- искусственно подать local update ниже OpenClaw offset;
- убедиться, что proxy его отбрасывает и делает
ack-dropped; - убедиться, что OpenClaw не оживляет старую сессию.
- Migration test:
- старый local server закрыт;
- новый server использует корректный volume;
- cloud fallback не начинает читать старую cloud очередь без virtual offset.
- Cloud fallback противоречит идеальной модели Telegram "один token - один Bot API server", поэтому это должен быть осознанный аварийный режим.
- Если удалить Docker volume, local server может потерять контекст и снова принести старые/разъехавшиеся updates.
- Если OpenClaw получает absolute
file_pathиз контейнера без rewrite, медиа может ломаться даже при здоровом local Bot API. - Если proxy начнет fallback-ить multipart/upload в cloud, большие файлы будут ломаться и могут создавать дубли side effects.
Дальше развиваем текущий proxy, а не заменяем его nginx:
tdlib/telegram-bot-apiдает правила и ограничения;Olegt0rr/telegram-localдает Docker packaging и reverse proxy практики;- наш proxy остается местом, где живет Telegram-specific fallback logic: offset floor, cloud cursor, stale update guard и file-size-aware
/filefallback.