Перейти к основному содержимому

WEB-прокси Telegram Desktop

b4 отдаёт поток MTProto поверх обычного HTTPS на отдельном хосте. Telegram Desktop 7.1.1 и новее открывает этот хост в скрытом WebView, тот поднимает один WebSocket обратно к b4 и мультиплексирует в него все соединения Telegram. Клиент не открывает MTProto-сокет, а в сети это выглядит как браузер, загружающий сайт.

Каждый мультиплексированный поток попадает в тот же код, что и обычное соединение MTProto: те же секреты, то же рукопожатие, та же маршрутизация до дата-центра. На клиенте ничего не устанавливается.

Хосту нужен публично доверенный сертификат на порту 443, поэтому это режим для b4 на VPS, а не для роутера за CGNAT.

Что должно быть выполнено заранее​

Четыре условия. Интерфейс проверяет только первое: карточка WEB-прокси скрыта, пока прокси-сервер выключен.

  • MTProto-прокси включён, и его слушающий сокет поднялся. Секреты загружаются только при старте этого сокета. Если порт уже занят, старт не проходит, секреты не загружаются, и релей отвечает на всё страницей-заглушкой.
  • У релея есть слушающий сокет. При пустом Порте relay релей - это виртуальный хост на собственном веб-сервере b4, поэтому порт веб-сервера 0 означает, что релея не существует. С собственным портом релей - слушатель MTProto-прокси, и веб-сервер в нём не участвует. Схему и порт задаёт сам Telegram, поэтому хост должен отвечать на https://<host>/ по 443 - либо самим b4, либо через проброс или обратный прокси. См. Порт relay.
  • Хост не общий с интерфейсом. Как только заголовок Host совпал, b4 занимает на этом имени все пути. Интерфейс, API и эндпоинты авторизации отдают там ту же заглушку.
  • TLS публично доверенный. Самоподписанного сертификата достаточно для интерфейса b4 и недостаточно здесь.
Настроенный релей при выключенном прокси-сервере отдаёт интерфейс b4

Виртуальный хост релея срабатывает, только когда включены оба переключателя. Если хост задан, WEB-канал включён, а прокси-сервер выключен, запросы к этому имени уходят на обычный веб-сервер b4, и публичное DNS-имя отвечает интерфейсом b4 со страницей входа, а не сайтом-заглушкой. Карточка WEB-прокси скрыта при выключенном прокси-сервере, поэтому такое состояние достижимо только правкой файла конфигурации.

Непригодный сертификат не останавливает b4

Если сертификат и ключ веб-сервера не загружаются, b4 пишет предупреждение и откатывается на обычный HTTP. Веб-сервер поднимается, релей поднимается вместе с ним, и на 443 не отвечает никто. Собственный порт релея ведёт себя иначе: пара, которая не загружается, своя или унаследованная, даёт ошибку в логе, и этот слушатель не поднимается вовсе, а отсутствие пары поднимает его как обычный HTTP.

Настройка​

  1. Направить хост на машину с b4. Публичное DNS-имя без лишнего. Поле отклоняет схему, порт, путь, учётные данные, IP-адрес и однокомпонентное имя; международное имя вводится в форме punycode (xn--).
  2. Отдавать его по доверенному TLS на 443. Либо сам b4 с корректным сертификатом и ключом - на порту веб-сервера или на собственном порту relay, либо обратный прокси, который завершает TLS, сохраняет заголовок Host или выставляет X-Forwarded-Host и разрешает WebSocket-апгрейд на /api/v1/ws.
  3. Включить MTProto-прокси и добавить хотя бы один секрет. Ссылки генерируются по секретам.
  4. Включить WEB-канал и указать хост релея в разделе Настройки, Telegram, WEB-прокси Telegram Desktop. Переключатель и хост действуют со следующего запроса; смена порта релея или его сертификата перезапускает только этот слушатель, MTProto-прокси и его соединения остаются на месте.
  5. Скопировать ссылку из окна Поделиться ссылкой для нужного секрета, строка WEB · Telegram Desktop 7.1.1+, и добавить её в Telegram Desktop.

Карточка WEB-прокси

Ссылка имеет вид https://t.me/webproxy?server=<хост>&secret=dd<32 hex-символа>.

Окно «Поделиться ссылкой» с прямой и WEB-ссылкой

Ссылка содержит не тот секрет, что показан в списке

Telegram Desktop не принимает fake-TLS секреты (ee) для WEB-записей, поэтому ссылка содержит padded-форму (dd) того же ключа, без домена, которым заканчивается ee-секрет. Ссылка, собранная вручную из видимого секрета, не работает; единственный корректный источник - окно «Поделиться ссылкой».

Смена хоста обесценивает все выданные ссылки

Токен в ссылке выводится из секрета и хоста вместе и пересчитывается по текущему хосту при каждом запросе. Смена хоста релея молча ломает все уже розданные ссылки, и каждую придётся выдать заново.

Порт relay​

Веб-сервер различает запросы только по заголовку Host. На хосте релея он отвечает как релей; на любом другом имени и на голом IP-адресе - как интерфейс b4 со страницей входа. Всё, что доставляет публичный 443 на этот порт, доставляет и то, и другое: проброс с WAN 443 роутера на порт веб-сервера или перенос самого веб-сервера на 443 ставит страницу входа на https://<публичный IP>/ рядом с заглушкой на https://<хост>/. Интерфейс остаётся за учётными данными, но его наличие видно любому, кто сканирует адрес.

Порт relay разделяет их. При включении WEB-канала в свежей настройке поле заполняется значением 443, потому что именно туда подключается Telegram; пустое поле - это общая схема выше, в которой находится каждая конфигурация, созданная до появления поля. С заданным портом MTProto-прокси открывает на нём собственный слушатель, на своём адресе привязки, а веб-сервер перестаёт отвечать на хост релея, пока этот слушатель поднят. Порт, который не удалось занять, или сертификат, который не загрузился, - ошибка в логе, и веб-сервер тем временем продолжает обслуживать хост релея, так что релей не проваливается в интерфейс:

  • Запрос к хосту релея обрабатывается ровно как раньше: страница-мост для корректного токена, WebSocket канала на /api/v1/ws, заглушка для всего остального.
  • Запрос к любому другому имени или к IP-адресу получает страницу-заглушку: 200 на / и 404 на любом другом пути. Интерфейса, его API и страницы входа на этом порту не существует.

TLS на порту релея по умолчанию - сертификат и ключ веб-сервера, та же пара, что и в общей схеме, и тогда именно она должна быть доверенной для хоста релея. У публичного сертификата в Настройки, Система, Веб-сервер есть побочный эффект для интерфейса: он переходит только на HTTPS, и каждый вход по IP из LAN показывает предупреждение браузера, потому что имя не совпадает. Сертификат для хоста relay в карточке принимает пару, которая используется только на порту релея, и интерфейс может остаться на обычном HTTP или со своим сертификатом. Отсутствие пары где бы то ни было означает обычный HTTP на порту релея с предупреждением в логе - это схема для завершающего TLS прокси перед b4. Порт, совпадающий с портом веб-сервера или MTProto-прокси, отклоняется при сохранении, а уже занятый на машине порт сообщается проверкой портов до записи конфигурации.

У собственного порта релея есть и свой переключатель Доступ из интернета, который виден под полем Порт relay, пока в нём указан порт, а также пока он включён при пустом поле, чтобы его можно было выключить. Он добавляет то же правило файрвола, что и переключатель MTProto-прокси, - правило, принимающее соединения на порт релея с любого адреса, как описано в разделе Доступ из интернета. При пустом поле собственного порта, который можно открыть, у релея нет: он доступен через порт веб-сервера, а его открывает только переключатель веб-сервера, вместе с интерфейсом, его API и страницей входа.

Роутер с интерфейсом на 7000

Со стороны WAN доступен порт релея, но не порт интерфейса: для порта релея включён Доступ из интернета, а если порт релея не сам 443, на него ведёт проброс с WAN 443. Порт интерфейса не открывается и не пробрасывается. https://<хост>/ попадает на релей, https://<публичный IP>/ - на заглушку, а интерфейс доступен только из LAN.

Порта нет в ссылке

Ссылка t.me/webproxy не содержит порта, и Telegram всегда открывает https://<хост>/. Порт релея - это то, куда должен прийти 443, а не то, что сообщается клиенту, поэтому работают только три схемы: сам 443, проброс с 443 или прокси на 443.

Страница-заглушка​

Каждый посетитель, который не является клиентом Telegram, видит заглушку: простую страницу «Service status». Она одна и та же на каждой установке b4, поэтому хост узнаваем как релей b4 для любого, кто уже видел такую.

Страница-заглушка в карточке заменяет её. Загружается один HTML-файл размером до 1 МиБ, он хранится как webproxy_page.html рядом с файлом конфигурации; тот же файл можно положить туда вручную. Отдаётся он как есть, со следующего запроса, с теми же кодами ответа, а удаляется кнопкой Удалить или удалением файла, после чего возвращается встроенная страница. Скачивание возвращает установленный файл для правки.

Страница должна быть самодостаточной. Релей отвечает этим файлом по любому пути на хосте релея, а на порту релея - по любому пути на любом имени, поэтому таблица стилей, скрипт или картинка по относительному пути вернутся той же самой страницей. Стили - inline, изображения - data: URI, а всё внешнее - только абсолютным URL на другом хосте. Страница-мост, которую загружает Telegram, отдельная, и её это не касается.

Что страница изменить не может

Заголовки ответа фиксированы: Cache-Control: no-store, Referrer-Policy: no-referrer, X-Content-Type-Options: nosniff и Content-Security-Policy, ограничивающий встраивание во фреймы. Путь канала /api/v1/ws и параметр ?bridge= на / сохраняют своё значение независимо от содержимого страницы.

Как убедиться, что всё работает​

Открытие хоста в браузере не доказывает ничего. Несовпавший хост, отсутствующий или неверный токен, истёкший тикет, обычный GET вместо WebSocket-апгрейда и исчерпанный лимит каналов дают одну и ту же страницу-заглушку, и ни один из этих случаев не логируется.

Подтверждает работу релея лог:

web carrier up from <ip> (secret=<label>)
web proxy new stream <n> from ...

и следом обычная строка ретрансляции для дата-центра, до которого дошёл поток. Такие соединения также видны на странице Трафик с меткой MTProto и именем секрета.

Границы​

  • Только Telegram Desktop, 7.1.1 и новее. У мобильных клиентов записи типа WEB нет.
  • Релей отвечает раньше проверки авторизации веб-сервера b4. Единственный барьер - токен: нет ни списка разрешённых источников, ни ограничения частоты, поэтому хоста вместе с секретом достаточно любому, у кого есть и то, и другое.
  • Все соединения Telegram одного клиента идут через один канал. Когда канал обрывается - по 90-секундному простою, нарушению протокола или просто закрытию клиента - разом заканчиваются все его потоки.
  • Макс. подключений и TCP-тайм-ауты здесь не действуют. WEB-путь ограничен отдельно: 256 одновременных каналов и 512 потоков на канал, и при достижении любого предела в лог ничего не пишется.