Роскомнадзор и Телеграм боты через прокси

Лучшей рекламы для прекрасного мессенджера и придумать невозможно — “несгибаемый Дуров держит оборону и стоит за конфиденциальность своих клиентов, как за свою жизнь”. Но суть данного поста не в маркетинговой составляющей блокировки 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 который сейчас уже отлично справляется со своей задачей


Nginx config

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/ в конфигурации приложения. Порт можете выбрать любой при вводе команды

Share post

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 32

    +1

    Спасибо за проделаннуб работу, возникло 2 вопроса


    • с помощью синей изоленты нет возможности скрестить бота с официальной mtproxy
    • не могу понять отчего http проксирование работает быстрее VPN решения которое умеет сжимать трафик
      0
      VPN требует ресурсов на установление канала связи, ну и латентность чуть больше.
        +2

        все-таки бот и клиент телеграма – это разные вещи, я сомневаюсь что клиент работает http-запросами на api, скорее всего у него свой бинарный протокол и другие сервера. так что боту socks/mtproxy не нужны, достаточно обычного http reverse proxy, что автор и проделал…


        другое дело что решение какое-то однобокое. если бот не должен получать сообщения или сообщения вытягиваются поллингом – вопросов нет, а иначе как будет вебхук работать – там же сам телеграм инициирует отправку нотификаций на адрес бота. нужен либо ещё один реверс от телеграма к боту, либо может проще бота развернуть где-то отдельно от основного сервиса? тогда и проксировать ничего не придётся… а данные можно боту скармливать уже с основного сервиса по http...

          0
          Так вебхуки уже другая история. Или РКН блокирует и входящий траффик от Telegram тоже?
            0
            Если телеграм придет с заблокированного адреса — то TCP-сессия не установится, в сторону таких адресов дропаются любые пакеты.
          0
          del
          +4
          Ну я бы ещё прикрыл фаерволом проксёвый порт от всего остального мира.
            0
            Если речь о nodejs, то можно использовать github.com/Bannerets/tdl#login-as-a-bot на основе tdlib, который в теории должен пробиваться через блокировку как и обычный телеграм клиент.
            Правда лично я его не тестил при подключении в качестве бота — только как обычного пользователя.
              +3
              proxy_pass https://api.telegram.org/;
              А резолвинг-то, наверное, все еще идет только при старте или релоаде nginx'а? Т.е. если вдруг поменяется IP, то все встанет?
                +1
                кажется, не должно быть проблем или надо добавить resolver
                nginx.org/ru/docs/http/ngx_http_core_module.html#resolver
                  0
                  вот так можно попробовать

                  location / {

                  resolver 8.8.8.8;
                  set $url «api.telegram.org»;
                  proxy_pass https://$url;

                  }

                    0
                    не совсем понял в чем профит от этого варианта
                      0
                      Я думаю, корни тут идут отсюда:
                      When you use a variable to specify the domain name in the proxy_pass directive, NGINX re‑resolves the domain name when its TTL expires.

                      Хотя если смотреть прямо в доках, то вроде как завязываться на переменную уже не обязательно.
                  0
                  <grammar_nazi>
                  Более лучше
                  Выберите уж что-то одно. И… спасибо за конфиг :)
                    0
                    сударь грамматический нацист просто не в курсе мема про «более лучше (одеваться)» :)
                      0
                      Спасибо большое поправил. Фейл:) Причем перечитал прежде чем публиковать раз 10)
                      0
                      Простите, я правильно понимаю, что вы решились не шифровать запросы до своего сервера в сети, по сути, которая является «прослушиваемой»?
                        0
                        нет конечно) обязательно https, но для быстрого старта, чтобы убедиться, что «работает» можно на http сделать — решил что так проще писать для инструкции)
                          0
                          При https есть проблема, раньше апи бота работало без валидации сертификата, а сейчас вроде как нет, поэтому вариант проксирования через nginx у вас просто не будет работать…
                        0
                        Есть способ еще проще через 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.
                          0
                          Спасибо! Как будет время выпущу попробую, дополню эту статью и соберу еще один контейнер
                          0
                          Не опасно ли бизнесу работать через телеграмм, на который наезжает государственная машина, и по закону? На него может спокойно наезжать роскомнадзор и он может внезапно найти на него управу, и отключить.
                          Тогда бизнес может оказаться без канала связи.
                          Я думаю, надо найти другие боты для связи с клиентами, для надежности.
                            0
                            Да, совершенно согласен. Поэтому используем телеграм только в качестве дублирующего канала для отправки уведомлений о новых заявках или проблемах. Основа идет через почту
                            0
                            правильно понимаю? трафик от бота до прокси не защищен?
                              0
                              В примере в статье да. В продакшне https
                                0
                                Простите за нудность, но — а зачем вы вообще используете именно nginx и именно так?
                                В целом, у вас задача стоит «просто отфорвардить запросы через разблокированное место». Есть вариант с nginx + stream, который я выше написал, есть haproxy, который может просто запроксить не трогая содержимое. Наконец, есть всякие другие подобные штуки которые делают то же самое. Все они позволяют 2 основных вещи:
                                1. Сохранить оригинальное шифрование.
                                2. Обеспечить доступ через разблоченный узел.
                                Схема «свой домен + сертификат + апстрим» конечно имеет право на жизнь, но она сложнее, требует выписки (и поддержки) своего сертификата, требует изменения в конфигурации приложения (имя домена) при том, что совершенно не дает профита.
                                  0
                                  А можно подробней описать более простой способ с сохранением шифрования и тд? Я бы с удовольствием на него перешел в работе) Я понимал, что мой вариант не идеален, но когда нужно что-то сделать срочно, то я делаю тем способом, который проверен)
                                    0
                                    Вот — comment_19159361.
                                      +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
                                      
                                        0
                                        Можно еще socat, там все вообще к одной маленькой команде сводится:
                                        socat TCP4-LISTEN:443,reuseaddr,fork,bind=serverip TCP4:api.telegram.org:443
                                        После чего все запросы на 443 порт вашего сервера будут проксироваться на api.telegram.org.
                                  0
                                  А зачем nginx если бот на nodejs поддерживает проксирование:
                                  const TelegramBot = require('node-telegram-bot-api')
                                  
                                  if (config.proxy) {
                                     options.request = {
                                        proxy: config.proxy
                                     }
                                  }
                                  
                                  const bot = new TelegramBot(config.token, options)
                                  


                                  Или я что то не так понял?
                                    0

                                    можно и так, но – сквида с авторизацией поднимать дольше и сложнее чем реверс на nginx сделать…


                                    лично я бы просто поднял tcp-тоннель с помощью socat, а на сервере прописал адрес тоннеля в /etc/hosts для api.telegram.org, тогда и с сертификатами не пришлось бы ничего городить. а уж научить systemd поднимать socat на автозапуске – вообще ничего не стоит…

                                  Only users with full accounts can post comments. Log in, please.