Более лучшей рекламы для прекрасного мессенджера и придумать невозможно — “несгибаемый Дуров держит оборону и стоит за конфиденциальность своих клиентов, как за свою жизнь”. Но суть данного поста не в маркетинговой составляющей блокировки Telegram на территории России. Если ваш Telegram бот перестал работать и вам нужно эту работу срочно восстановить, добро пожаловать под кат.
Вчера вечером мы столкнулись с проблемой, с которой было ожидаемо столкновение. API сервер одного нашего клиента располагался в Heroku. Вчера недовольный клиент мне пишет (в Telegram, разумеется), что на сайте информация рандомно то появляется, то нет. Сам сайт (приложение на NodeJS) уже был заранее перенесен на Московский сервер для уменьшения пинга.
Спустя полчаса изучения проблемы был получен простой вывод: Роскомнадзор заблокировал часть адресов heroku. Ротация серверов heroku происходит на уровне DNS и DNS иногда отдавал рабочий IP, иногда — нет. К слову, выяснять причину проблемы было довольно таки непросто — когда тестировали мы с разработчиками — проблемы не было. Когда тестировал клиент — были. Уже появлялись мысли ответить клиенту великую фразу разработчика “у меня на компе все работает”.
Решение было довольно простым — мы перенесли API сервер приложения на Питерский сервер клиента и там его спокойно развернули. Все заработало отлично, кроме, конечно же, интеграции с Telegram. Поскольку отказаться от этой интеграции не является возможным, т.к. нет достойной альтернативы, мы начали искать решение данной проблемы. С родным клиентом Telegram все просто — в него уже встроено взаимодействие с proxy сервером и его настройка отнимает несколько секунд. С Bot API все немного по другому. Приложение взаимодействует с https://api.telegram.org/ для каждого действия Telegram бота, а этот адрес, разумеется, заблокирован РКН.
В качестве экспресс-решения проблемы сразу пришло в голову подключить API сервер клиента к нашей OpenVPN сети для обхода этой блокировки. Решение было сразу же отвергнуто, т.к. скорость ответа оставляла желать лучшего. Гугл и Яндекс не смогли поделиться со мной полезной информацией по решению этого вопроса.
В результате пришла в голову простая и очевидная мысль — поднять самостоятельно простейший прокси сервер для соединения в телеграм. Ниже предоставлен конфиг nginx который сейчас уже отлично справляется со своей задачей
server {
listen 80;
server_name my-telegram-proxy.server;
location / {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://api.telegram.org/;
client_max_body_size 100M;
}
}
Далее в приложении я подменил url BOT API для взаимодействия с telegram — вместо
https://api.telegram.org/bot
написал
http://my-telegram-proxy.server/bot
и интеграция с Bot Api успешно заработала
Для большего удобства создал docker контейнер с подробной инструкцией по его использованию. Это позволит вам поднять свою telegram bot proxy одной командой за считанные секунды
https://hub.docker.com/r/zvinger/docker-proxy-rkn/builds/
Пример команды:
docker run -d -p 8012:80 zvinger/docker-proxy-rkn
и указываете http://адрес.сервера:8012/ в конфигурации приложения. Порт можете выбрать любой при вводе команды
Комментарии (32)
Taraflex
26.09.2018 09:42Если речь о nodejs, то можно использовать github.com/Bannerets/tdl#login-as-a-bot на основе tdlib, который в теории должен пробиваться через блокировку как и обычный телеграм клиент.
Правда лично я его не тестил при подключении в качестве бота — только как обычного пользователя.
Merlyel
26.09.2018 10:20+1proxy_pass https://api.telegram.org/;
А резолвинг-то, наверное, все еще идет только при старте или релоаде nginx'а? Т.е. если вдруг поменяется IP, то все встанет?aol-nnov
26.09.2018 11:40кажется, не должно быть проблем или надо добавить resolver
nginx.org/ru/docs/http/ngx_http_core_module.html#resolver
reci
26.09.2018 11:09<grammar_nazi>Более лучше
Выберите уж что-то одно. И… спасибо за конфиг :)aol-nnov
26.09.2018 11:38сударь грамматический нацист просто не в курсе мема про «более лучше (одеваться)» :)
zvinger Автор
26.09.2018 12:15Спасибо большое поправил. Фейл:) Причем перечитал прежде чем публиковать раз 10)
SLASH_CyberPunk
26.09.2018 12:11Простите, я правильно понимаю, что вы решились не шифровать запросы до своего сервера в сети, по сути, которая является «прослушиваемой»?
zvinger Автор
26.09.2018 12:15нет конечно) обязательно https, но для быстрого старта, чтобы убедиться, что «работает» можно на http сделать — решил что так проще писать для инструкции)
SLASH_CyberPunk
26.09.2018 13:31При https есть проблема, раньше апи бота работало без валидации сертификата, а сейчас вроде как нет, поэтому вариант проксирования через nginx у вас просто не будет работать…
onlinehead
26.09.2018 12:17Есть способ еще проще через streams (и правильнее, так как шифрование сохранится) с тем же Nginx, и даже ничего в коде скрипта менять не придется.
На стороне приложения пишем в /etc/hosts:
ip.of.my.proxy api.telegram.org
Для Nginx на проксе пишем:
stream {
# Конфигурация апстрима
upstream tgapi {
server api.telegram.org:443;
}
# Вот этот блок ради того, чтобы можно было один сервер использовать как прокси для нескольких имен
map $ssl_preread_server_name $upstream {
hostnames;
default tgapi;
api.telegram.org tgapi;
}
server {
listen 443;
ssl_preread on;
proxy_pass $upstream;
}
}
Кстати, в большинстве дистрибутивов nginx собран без stream, но оно есть в nginx-full в официальной репе самого nginx.zvinger Автор
26.09.2018 12:56Спасибо! Как будет время выпущу попробую, дополню эту статью и соберу еще один контейнер
Green2
26.09.2018 12:27Не опасно ли бизнесу работать через телеграмм, на который наезжает государственная машина, и по закону? На него может спокойно наезжать роскомнадзор и он может внезапно найти на него управу, и отключить.
Тогда бизнес может оказаться без канала связи.
Я думаю, надо найти другие боты для связи с клиентами, для надежности.zvinger Автор
26.09.2018 12:29Да, совершенно согласен. Поэтому используем телеграм только в качестве дублирующего канала для отправки уведомлений о новых заявках или проблемах. Основа идет через почту
loderunner84
26.09.2018 12:30правильно понимаю? трафик от бота до прокси не защищен?
zvinger Автор
26.09.2018 12:30В примере в статье да. В продакшне https
onlinehead
26.09.2018 12:43Простите за нудность, но — а зачем вы вообще используете именно nginx и именно так?
В целом, у вас задача стоит «просто отфорвардить запросы через разблокированное место». Есть вариант с nginx + stream, который я выше написал, есть haproxy, который может просто запроксить не трогая содержимое. Наконец, есть всякие другие подобные штуки которые делают то же самое. Все они позволяют 2 основных вещи:
1. Сохранить оригинальное шифрование.
2. Обеспечить доступ через разблоченный узел.
Схема «свой домен + сертификат + апстрим» конечно имеет право на жизнь, но она сложнее, требует выписки (и поддержки) своего сертификата, требует изменения в конфигурации приложения (имя домена) при том, что совершенно не дает профита.zvinger Автор
26.09.2018 12:46А можно подробней описать более простой способ с сохранением шифрования и тд? Я бы с удовольствием на него перешел в работе) Я понимал, что мой вариант не идеален, но когда нужно что-то сделать срочно, то я делаю тем способом, который проверен)
onlinehead
26.09.2018 12:57+1Вот так будет выглядеть конфигурация для haproxy, которая будет делать то же самое (но только для одного домена, что не всегда удобно):
resolvers default nameserver default 4.2.2.2:53 frontend localhost bind *:443 option tcplog mode tcp default_backend nodes backend nodes mode tcp balance roundrobin option ssl-hello-chk server api api.telegram.org:443 check resolvers default
punkkk
26.09.2018 16:56А зачем nginx если бот на nodejs поддерживает проксирование:
const TelegramBot = require('node-telegram-bot-api') if (config.proxy) { options.request = { proxy: config.proxy } } const bot = new TelegramBot(config.token, options)
Или я что то не так понял?constb
27.09.2018 06:07можно и так, но – сквида с авторизацией поднимать дольше и сложнее чем реверс на nginx сделать…
лично я бы просто поднял tcp-тоннель с помощью socat, а на сервере прописал адрес тоннеля в /etc/hosts для api.telegram.org, тогда и с сертификатами не пришлось бы ничего городить. а уж научить systemd поднимать socat на автозапуске – вообще ничего не стоит…
time2rfc
Спасибо за проделаннуб работу, возникло 2 вопроса
Nikobraz
VPN требует ресурсов на установление канала связи, ну и латентность чуть больше.
constb
все-таки бот и клиент телеграма – это разные вещи, я сомневаюсь что клиент работает http-запросами на api, скорее всего у него свой бинарный протокол и другие сервера. так что боту socks/mtproxy не нужны, достаточно обычного http reverse proxy, что автор и проделал…
другое дело что решение какое-то однобокое. если бот не должен получать сообщения или сообщения вытягиваются поллингом – вопросов нет, а иначе как будет вебхук работать – там же сам телеграм инициирует отправку нотификаций на адрес бота. нужен либо ещё один реверс от телеграма к боту, либо может проще бота развернуть где-то отдельно от основного сервиса? тогда и проксировать ничего не придётся… а данные можно боту скармливать уже с основного сервиса по http...
zvinger Автор
Так вебхуки уже другая история. Или РКН блокирует и входящий траффик от Telegram тоже?
inkvizitor68sl
Если телеграм придет с заблокированного адреса — то TCP-сессия не установится, в сторону таких адресов дропаются любые пакеты.
im_stD
del