> [!mirror] Резервное зеркало > Актуальная версия этой страницы — на основной вики: [wiki.zapret.moe/mtproxy/telegram-wss-transport](https://wiki.zapret.moe/mtproxy/telegram-wss-transport) # 🕸️ WSS для Telegram: MTProto внутри WebSocket ![[telegram-wss-limits-header.jpg]] > [!info] О чём заметка > Как устроен транспорт, на котором ZaStoGram и мосты вроде tg-ws-proxy подключаются к Telegram без VPN: что именно уходит в сеть, какие правила ставит сервер, куда клиент идёт, когда веб-вход Telegram закрыт, и кто при этом видит трафик. Статья переписана 16 октября 2026 года по текущему коду; что из этого ломается на практике (стикеры, звонки, лимиты Cloudflare), разобрано в парной заметке [[mtproxy/telegram-wss-limits|Ограничения WSS: что не работает и почему]]. > [!warning] Откуда взяты данные > Telegram не публиковал описания своих веб-релеев: всё ниже восстановлено по исходному коду и живым замерам, и любая деталь может поменяться без предупреждения. > - **Код:** ZaStoGram для Android 1.1.30 (15 октября 2026 года, база — Telegram 13.0.2), ZaStoGram Desktop `zsg-7.3.1` (16 октября 2026 года, база — Telegram Desktop 7.3.1), [tg-ws-proxy v1.11.2 от 11 октября 2026 года](https://github.com/Flowseal/tg-ws-proxy/releases) и модуль `telegram_proxy` из ZapretGUI на 16 октября. > - **Замеры в России:** 8–9 августа 2026 года, в сети провайдера, который разбирает трафик системой DPI; они записаны в сообщениях коммитов ZaStoGram. > - **Замеры 16 октября 2026 года:** с сервера в Германии. Они показывают, как ведут себя сами релеи, но ничего не говорят о блокировках у российских провайдеров. --- ## TL;DR 1. WSS-транспорт — это обычный обфусцированный MTProto, который едет внутри кадров WebSocket поверх настоящего TLS на порт 443 доменов `kwsN.web.telegram.org`, тех же, что обслуживают браузерный Telegram Web. Он обходит блокировку адресов датацентров Telegram, а не распознавание протокола. 2. Сервер ставит два правила, и оба нарушаются молча: первый кадр должен содержать не меньше 64 байт, и в одном кадре должно быть не больше одного MTProto-пакета. Кадр в 63 байта получает тишину до таймаута — это перепроверено 16 октября 2026 года. 3. Веб-релеи есть у всех пяти датацентров, но адреса входа не взаимозаменяемы: адрес DC2/DC4 на чужие имена отвечает `302`, адрес DC1/DC3 молчит. Исключение нашлось 16 октября: адрес DC5 `149.154.170.100` принял все десять имён. У DC2/DC4 рабочих адресов два, `149.154.167.220` и `149.154.167.99`, и с 16 октября 2026 года ZaStoGram и ZapretGUI держат оба: если провайдер закрыл один, клиент сам переходит на второй. 4. С конца сентября 2026 года ZaStoGram при закрытом релее идёт не на прямой адрес датацентра, а по лестнице: 20 доменов за Cloudflare, затем три туннеля на Cloudflare Workers. Прямого TCP в конце лестницы больше нет. 5. За это приходится платить: на запасных ступенях транспортный слой видят Cloudflare и владельцы доменов и воркеров. Переписка остаётся зашифрованной ключом MTProto, но номер датацентра, объём и время соединений им доступны. 6. У бесплатного воркера Cloudflare лимит 100 000 запросов в сутки, и трёх воркеров к вечеру уже не хватает. Пока DC203, где лежат медиа аккаунтов без Premium, ходил только через воркеры, это оставляло его файлы без пути. С 16 октября 2026 года DC203 идёт через те же домены за Cloudflare: `kws203.‹домен›` отвечает настоящим MTProto. 7. Звонки этот транспорт не переносит: голос и видео Telegram идут по UDP мимо него. --- ## Какую блокировку обходит WSS Обход блокировок Telegram решает две разные задачи. Первая — когда провайдер узнаёт соединение по виду: по TLS-рукопожатию, по почерку клиента, по характерному первому пакету. С этим работают пакетные инструменты вроде [[Zapret2/Zapret2|zapret]] и правки TLS-почерка в самом клиенте; почему это делается на стороне клиента, разобрано в [[mtproxy/ja4-sni-client-side|заметке про JA4 и SNI]]. Вторая задача возникает, когда провайдеру всё равно, как выглядит трафик, потому что он режет сами адреса. Диапазоны датацентров Telegram (`149.154.160.0/20`, `91.105.192.0/23`, несколько сетей `91.108.x.0/22` и пара соседних) известны и компактны, и закрыть их целиком дешевле, чем разбирать протокол. Против такой блокировки фрагментация пакетов бесполезна: пакет просто не доезжает до адресата. WSS решает вторую задачу. У Telegram, кроме адресов датацентров для мобильных и настольных приложений, есть веб-вход для браузерной версии. Он живёт на порту 443 с обычными сертификатами на `*.web.telegram.org`, и закрыть его тем же способом дороже: браузерным Telegram пользуются миллионы людей. Если завернуть поток приложения в протокол, которым пользуется браузер, соединение на уровне адреса и имени выглядит как визит на сайт Telegram. Проще говоря: почерк соединения остаётся прежним, меняется адрес, на который клиент стучится. Это должен быть адрес, который провайдеру неудобно закрывать. ## Как устроено соединение Браузер общается с веб-версией Telegram по WebSocket — протоколу, который превращает обычное HTTPS-соединение в постоянный двусторонний канал. Данные в нём идут не потоком, а отдельными порциями с коротким заголовком, кадрами (frames); правила кадров описаны в [RFC 6455, стандарте WebSocket](https://datatracker.ietf.org/doc/html/rfc6455). WSS — это тот же WebSocket поверх TLS. Сервер, который принимает такие подключения и передаёт их дальше во внутреннюю сеть Telegram, дальше называется релеем. Готовое подключение — пять вложенных слоёв: ![[wiki-anim-telegram-wss-stack.svg|Схема: слои соединения Telegram по WebSocket]] Внешний TLS маскирует соединение: наблюдатель видит HTTPS к домену Telegram. Слой obfuscated2 остался тем же, что в обычном TCP-подключении Telegram: он превращает поток в шум без узнаваемых заголовков. Самый нижний слой, MTProto с ключом авторизации, не трогает ни один транспорт. Переписку расшифровывают только устройство и серверы Telegram. ### Рукопожатие по шагам Оба клиента ZaStoGram делают одно и то же: 1. **TCP к адресу релея.** Клиент подключается к адресу, зашитому в код для нужного датацентра, а не к имени из DNS. Если адрес не отвечает, клиент один раз пробует имя через DNS и помнит этот выбор 30 минут. 2. **TLS.** В поле имени сервера (SNI) и в проверке сертификата стоит `kwsN.web.telegram.org`, даже когда подключение идёт по IP. Сертификат проверяется по-настоящему: на Android — через OpenSSL-совместимую библиотеку с минимальной версией TLS 1.2, на Desktop — средствами Qt. Подделки TLS-почерка под браузер нет ни в одном клиенте: рукопожатие уходит с отпечатком своей криптобиблиотеки, а не Chrome. 3. **HTTP Upgrade.** Запрос Android-клиента выглядит так (Desktop отличается только строкой `User-Agent` с `Windows NT 10.0`): ```http GET /apiws HTTP/1.1 Host: kws2.web.telegram.org Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: <16 случайных байт в base64> Sec-WebSocket-Version: 13 Sec-WebSocket-Protocol: binary Origin: https://web.telegram.org User-Agent: Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36 ``` 4. **Проверка ответа.** Сервер отвечает `101 Switching Protocols`. Оба клиента сверяют заголовок `Sec-WebSocket-Accept` — хеш SHA-1 от отправленного ключа и константы из RFC 6455 — и рвут соединение при несовпадении. 5. **Обмен кадрами.** Дальше идут бинарные кадры, каждый исходящий маскируется четырьмя случайными байтами, как требует стандарт. На служебный `ping` клиент отвечает `pong`, кадр `close` считается обрывом. Строгость к входящим кадрам у клиентов разная. Android отклоняет всё, что запрещено стандартом: выставленные зарезервированные биты, замаскированные кадры от сервера, служебные кадры длиннее 125 байт, текстовые кадры, кадр-продолжение без начала. На каждый такой отказ у него свой код в журнале, всего их 29, от `wss_tls_verify_failed` до `wss_accept_mismatch`. Desktop мягче: он снимает маску, если сервер её всё-таки поставил, и склеивает любые кадры с данными в один поток. ## Что едет внутри кадров Внутри кадров лежит тот же поток, что ушёл бы в голый TCP. Начинается он с 64-байтного заголовка obfuscated2, и устроен этот заголовок так: | Байты | Что в них | |---|---| | 0–7 | случайные, сервер их пропускает | | 8–55 | ключ и начальное значение шифра AES-256-CTR; те же байты в обратном порядке дают ключ для ответов сервера | | 56–59 | тег протокола: `0xefefefef`, `0xeeeeeeee` или `0xdddddddd` | | 60–61 | номер датацентра или случайные байты (см. ниже) | | 62–63 | случайные | Затем заголовок шифруется этим же ключом, но наружу из зашифрованного уходят только последние 8 байт, с тегом и номером датацентра; первые 56 байт, включая сам ключ, идут как есть. Проще говоря: ключ к остальному потоку лежит в первых байтах этого же потока. Обфускация делает поток похожим на случайный шум и прячет его от поиска по сигнатурам, но тот, кто видит поток целиком, расшифрует его без труда. Защиту содержимого даёт только следующий слой — MTProto с ключом авторизации. Режимы и теги — те же, что в MTProxy; они разобраны в [[Zapret/mtproto/01-protocol|описании протокола MTProxy]]. Байты 60–61 в WSS заполняются по-разному в зависимости от того, куда идёт соединение. Для веб-релея Telegram ZaStoGram оставляет их случайными, как Telegram Web: имя `kwsN` или `kwsN-1` уже говорит релею, какой это датацентр и обычное ли это соединение или загрузка файлов. Номер датацентра пишется только туда, где имени для этого нет: в подключения через MTProxy-секрет, в туннель через воркер (он идёт к датацентру голым TCP) и в домены за Cloudflare. В августе 2026 года оба клиента писали номер и для релея, и релей отвечал ошибкой `-444`; это исправлено. Медийные соединения Telegram помечает отрицательным номером датацентра. На веб-релее такому соединению соответствует имя с суффиксом `-1`: `kws4-1.web.telegram.org` вместо `kws4.web.telegram.org`. Адрес у обоих имён один, суффикс различает только класс трафика. ## Два правила нарезки, которые нарушаются молча Поток байт можно разложить по кадрам как угодно: весь заголовок одним кадром или по байту, пакет целиком или по частям. Стандарт WebSocket это разрешает. Релей Telegram — нет, и ошибку он не сообщает. > [!tip] Правила веб-релея Telegram > **Первое:** первый бинарный кадр после апгрейда должен содержать не меньше 64 байт, то есть весь заголовок obfuscated2. Релей разбирает заголовок только из первого кадра и к этому вопросу больше не возвращается: досылка недостающих байт следующим кадром соединение не спасает. > > **Второе:** в одном кадре — не больше одного MTProto-пакета. Релей разбирает первый пакет кадра и молча выбрасывает всё, что идёт за ним. Резать один пакет на несколько кадров можно. Первое правило измерено 8 августа 2026 года в российской сети: первый кадр в 63 байта получил 0 ответов из 10 попыток, в 64 байта — 8 из 8. 16 октября 2026 года замер повторён на `kws2` с сервера в Германии, по пять попыток на каждую длину, и результат тот же. ![[telegram-wss-first-frame.png]] Хуже всего здесь то, как выглядит отказ. При первом кадре в 48–63 байта соединение живо, TLS в порядке, апгрейд прошёл, но ответа нет. Со стороны клиента это неотличимо от блокировки у провайдера, и ошибку легко искать не там. Только совсем короткий кадр, 32–33 байта, сразу получает от релея кадр `close` с текстом `404`. Второе правило нашли 9 августа 2026 года на создании ключа авторизации. Перед вторым шагом рукопожатия клиент подтверждает предыдущий ответ сервера, и подряд идут два пакета, `msgs_ack` и `req_DH_params`. Отправленные двумя кадрами, они получили ответ `server_DH_params_ok`. Склеенные в один кадр, они не получили ничего: сервер принял подтверждение, а запрос для него не существовал. Пользователь видел это так: переписка работает, а картинки из датацентров, к которым у клиента ещё нет ключа, не грузятся вовсе ([коммит ZaStoGram dadaf092d от 9 августа 2026 года](https://git.zapret.moe/zastogram/ZaStoGram/commit/dadaf092def4d23efefb7e031616b46240c2bc6b)). Проще говоря: кадр для релея — единица разбора, а не способ упаковки. Первый кадр должен вместить заголовок целиком, а каждый следующий должен заканчиваться ровно там, где кончается пакет. В коде клиентов это выглядит так. Android копит начальные байты в отдельном буфере и не выпускает первый кадр, пока их меньше 64; дальше при постановке в очередь записывается размер каждого пакета, и каждый пакет уходит своим кадром ([первая из этих правок — коммит f22da13d2 от 8 августа 2026 года](https://git.zapret.moe/zastogram/ZaStoGram/commit/f22da13d2947207b64526492f5cbd46ae06571d9)). Desktop склеивает 64-байтный заголовок с первым пакетом в один кадр и дальше делает один кадр на каждый вызов записи, а вызов записи у него и так один на пакет. ## Пять датацентров и три адреса входа Адрес, на который клиент открывает TCP, дальше называется адресом входа (ingress). У каждого датацентра он свой, и ZaStoGram держит их таблицей: | Датацентры | Адреса входа в клиентах | Адрес из DNS | Имена | |---|---|---|---| | DC1, DC3 | `149.154.174.100` | тот же | `kws1`, `kws3` и их `-1` | | DC2, DC4 | `149.154.167.220`, затем `149.154.167.99` | `149.154.167.99` | `kws2`, `kws4` и их `-1` | | DC5 | `149.154.170.100` | тот же | `kws5`, `kws5-1` | У DC2 и DC4 рабочих адресов входа два. DNS на имена `kws2`, `kws4` и даже на сам `web.telegram.org` отдаёт `149.154.167.99`: 16 октября 2026 года так ответили пять публичных резолверов, от Cloudflare и Google до «Яндекса». Адреса `149.154.167.220` в DNS нет, но именно его месяцами держали зашитым ZaStoGram, tg-ws-proxy и ZapretGUI. В ZapretGUI ещё с марта 2026 года рядом с `.99` было записано «не используется — .220 стабильнее для медиа», но замера за этой фразой не нашлось. 15 октября пользователь tg-ws-proxy [сообщил, что провайдер закрыл `149.154.167.220` по IP](https://github.com/Flowseal/tg-ws-proxy/issues/1450): с одним зашитым адресом такой клиент остаётся с DC2 и DC4 только через DNS-имя или Cloudflare. Какой из двух адресов лучше, проверили 16 октября: по 25 полных подключений на каждое из трёх имён, от TCP до первого ответа Telegram. ![[telegram-wss-dc24-two-addresses.png]] Оба адреса ответили 75 раз из 75, а разница в 3–5% меньше разброса самого TLS-рукопожатия. Проще говоря: адреса равноценны, и важно не какой из них выбрать, а держать оба. Так и сделано 16 октября 2026 года в ZaStoGram для Android ([коммит f7159aabd](https://git.zapret.moe/zastogram/ZaStoGram/commit/f7159aabd3e62b76e711e3859ae604901a95b76e)), в ZaStoGram Desktop ([коммит 4399dd9626](https://git.zapret.moe/zastogram/ZaStoGram_desktop/commit/4399dd96261134065c7899a7d8c537ca64bcc462)) и в ZapretGUI ([коммит cb72426c](https://git.zapret.moe/zapretdiscordyoutube/zapretgui/commit/cb72426c8de4d15da363968845ea8725fad7656e)). Устроено одинаково: - первым клиент пробует адрес, который последним ответил в этой сети, а по умолчанию `.220`: он месяцами работает в российских сетях; - если адрес не ответил, следующие соединения DC2 и DC4 идут на второй адрес, а отказавший две минуты стоит в очереди последним; - имя из DNS остаётся последним кандидатом, когда отказали оба адреса: второй зашитый адрес не зависит от резолвера, который провайдер тоже может подменить. Изменение войдёт в ближайшие сборки; tg-ws-proxy на 16 октября по-прежнему знает только `.220`. У всех имён есть и IPv6-записи: у DC1/DC3 и DC5 по два адреса, у DC2/DC4 один. Подставить адрес чужого датацентра в общем случае нельзя. 16 октября 2026 года каждая пара «адрес + имя» была проверена настоящим запросом создания ключа: ![[telegram-wss-ingress-matrix.png]] Адреса DC2/DC4 на чужие имена отвечают `302 Found` с заголовком `X-Redirect-Host`, в котором сервер прямо называет имя, на которое пришли. Адрес DC1/DC3 на чужие имена принимает соединение и молчит. Клиент с включённой проверкой сертификата до этих ответов даже не доходит: на чужое имя адрес DC2/DC4 отдаёт сертификат `*.telegram.org`, а адрес DC1/DC3 — `*.telesco.pe`, и проверка имени их не пропускает. Адрес DC5 повёл себя иначе: он принял все десять имён и на каждое ответил настоящим MTProto. В августе этого не проверяли. Пока это наблюдение одного дня и одной сети: ни один клиент на него не опирается, и считать его запасным входом для всех датацентров рано. > [!note] Откуда взялся миф «WSS работает только для DC2 и DC4» > До 8 августа 2026 года и Desktop-клиент, и мосты держали один адрес `149.154.167.220` на все датацентры. Попытки достучаться через него до `kws1` или `kws5` давали `302`, и отсюда сделали вывод, что у DC1, DC3 и DC5 веб-релеев нет. Таблицу адресов по датацентрам Desktop получил [коммитом 7f3ceffb32 от 8 августа 2026 года](https://git.zapret.moe/zastogram/ZaStoGram_desktop/commit/7f3ceffb32397beb86fc58ed1a59f59eff0be4bd). Миф живёт до сих пор: подпись тумблера в Desktop-клиенте — «Route via WSS (web, DC2/DC4 only)», tg-ws-proxy по умолчанию идёт на релей только для DC2 и DC4, а ZapretGUI до 16 октября 2026 года помечал DC1, DC3 и DC5 как неподтверждённые и в диагностике проверял `kws1`…`kws5` на одном `.220`, получая те же `302`. Отдельный случай — DC203. Это датацентр, из которого Telegram отдаёт медиа аккаунтам без Premium, и своего веб-релея у него нет. До 16 октября 2026 года клиенты возили его только туннелем через воркер (о нём ниже), и его медиа первыми вставали, когда у воркеров кончался суточный лимит. 16 октября выяснилось, что домены за Cloudflare несут и его: `kws203.‹домен›` на всех проверенных доменах ответил настоящим `resPQ`. С этого дня DC203 в ZaStoGram для Android ([коммит 7c6cfb539](https://git.zapret.moe/zastogram/ZaStoGram/commit/7c6cfb539c78444a4456a82a8a767bff9f0d7721)), Desktop ([коммит 09fefd7e6e](https://git.zapret.moe/zastogram/ZaStoGram_desktop/commit/09fefd7e6eb2f5acb3e908fe5b9ef6590d6366f4)) и ZapretGUI ([коммит 676f111c](https://git.zapret.moe/zapretdiscordyoutube/zapretgui/commit/676f111c37aa331fc9e340a79e5ce256db58dd99)) идёт как датацентр с закрытым релеем: со второй ступени лестницы. ## Когда релей закрыт: лестница запасных путей Релей нужного датацентра бывает недоступен из конкретной сети. В замере 9 августа 2026 года в одной российской сети из четырёх проверенных путей открыт был один: релей DC2 работал, а релей DC1 не отвечал ни по IPv4, ни по IPv6. Пользователь видел, что фотографии грузятся, а эмодзи и реакции из DC1 — нет. Как проверить это в своей сети и почему `ping` ничего не доказывает, разобрано в [[mtproxy/telegram-wss-limits|заметке об ограничениях]]. В августе ZaStoGram на такой случай переключал датацентр на обычное прямое соединение на 10 минут ([коммит 96c4549a4 от 9 августа 2026 года](https://git.zapret.moe/zastogram/ZaStoGram/commit/96c4549a4d088521ab5515928f7acd0ee6f452c1)). К концу сентября выяснилось, что в сетях, где закрыт релей, прямой адрес датацентра закрыт тоже: 27 попыток к медиа DC1 по мобильной сети не дали ни одного TCP-подключения. Поэтому сейчас оба клиента ищут путь в таком порядке: ![[telegram-wss-fallback-ladder.png]] **Ступень 1: веб-релей Telegram.** Обычный путь, описанный выше. Неудачей считается попытка, которая не дошла до TCP, не прошла рукопожатие, получила отказ на апгрейде или не получила ответа на первые байты MTProto. Последнее ловит «чёрную дыру»: релей принимает TLS и апгрейд, но глотает данные, и без этого правила клиент ходил бы к нему бесконечно ([коммит f875caa03 от 27 августа 2026 года](https://git.zapret.moe/zastogram/ZaStoGram/commit/f875caa033145ff2c103e0ca5a1e054d4d94f5ff)). После трёх неудач подряд релей уходит на паузу на 2 минуты; каждая следующая пауза вдвое длиннее, до 30 минут. **Ступень 2: 20 доменов за Cloudflare.** Клиент подключается к имени вида `kwsN.‹домен›.co.uk`, за которым стоит Cloudflare, а уже Cloudflare передаёт соединение в датацентр Telegram. Приём называется фронтированием: провайдер видит соединение с обычным адресом Cloudflare, а не с Telegram. Список доменов взят из tg-ws-proxy, в коде он хранится в закодированном виде, у каждого домена два адреса Cloudflare ([коммит 006cb614f от 27 сентября 2026 года](https://git.zapret.moe/zastogram/ZaStoGram/commit/006cb614fe844f7c49b8cfea108dcf061714a427)). По комментарию в коде, около 40% попыток к этим доменам Cloudflare отклоняет кодом `503`, поэтому клиент повторяет апгрейд до восьми раз на том же TLS-соединении, а домены уходят на паузу только после шести неудач подряд. Рабочим домен считается, когда через него пришло 32 КБ данных. Desktop с 2 октября 2026 года (выпуск `zsg-7.3.1`) не ждёт паузы релея: через полсекунды после начала подключения к релею он параллельно начинает подключение через домен. **Ступень 3: туннель через воркер.** Воркер (Worker) — небольшая программа, которую Cloudflare запускает на своих серверах по запросу. Воркер ZaStoGram принимает WebSocket по адресу `…workers.dev/apiws?dst=‹адрес датацентра›` и сам открывает TCP до этого адреса; адреса вне сетей Telegram он не пропускает. Воркеров три, на трёх разных учётных записях Cloudflare, и каждая установка начинает со случайного. Причина — [лимит бесплатного тарифа Cloudflare: 100 000 запросов в сутки, со сбросом в полночь UTC и ошибкой 1027 после исчерпания](https://developers.cloudflare.com/workers/platform/limits/). 8 октября 2026 года единственный тогда воркер исчерпал лимит к вечеру, и медиа DC203 встали у всех пользователей ([коммит af99f5b72 от 8 октября 2026 года](https://git.zapret.moe/zastogram/ZaStoGram/commit/af99f5b7210ddcea0269443133bb4e8ac2f20c0c)); воркер, ответивший `429`, теперь уходит на паузу с первого отказа. Трёх воркеров тоже мало: к 16:20 UTC 16 октября два из трёх снова отвечали `429`. Туннель самый медленный: на мобильных сетях соединения с Cloudflare замирают примерно после 16 КБ, поэтому файлы через него качаются частями по 8 КБ, а соединение заменяется новым после нескольких килобайт ответа. **Ступень 4: снова домены за Cloudflare.** Если на паузе всё, клиент идёт через домены, не глядя на паузы. Комментарий в коде объясняет это так: прямой путь — ровно то, что такие сети блокируют, и у тестировщика DC2 минутами висел в подключении, пока домены для DC4 отвечали за 100 мс. Прямое TCP-подключение осталось только для датацентров, у которых нет ни одной ступени: тестового сервера Telegram и CDN-датацентров — отдельных серверов Telegram для раздачи популярных файлов, у которых веб-релеев нет. Паузы клиент считает отдельно для каждой сети. Android различает Wi-Fi и мобильную связь, Desktop — лимитное и безлимитное подключение. Причина практическая: релей DC1 дома работал, а после мобильной сети, где он закрыт, датацентр ещё до получаса оставался в туннеле. Паузы релеев сохраняются на диск и после перезапуска действуют не дольше 10 минут. Короткий всплеск таймаутов в пределах двух секунд считается одной неудачей, а таймаут к адресу, который принимал TCP в последние 30 секунд, — потерей пакетов, а не закрытым релеем. ### Кто видит трафик на каждой ступени На первой ступени TLS заканчивается на сервере Telegram, и транспортный слой видит только Telegram. На второй и третьей TLS заканчивается на Cloudflare: сертификат выдан на домен фронта или на `workers.dev`, а не на `web.telegram.org`. Дальше внутри идёт поток obfuscated2, а его ключи лежат в первых 64 байтах этого же потока, поэтому любой, кто видит поток после TLS, может снять обфускацию. Воркер ZaStoGram, судя по его исходнику, так и делает: читает из заголовка номер датацентра и пишет его в свой журнал вместе с объёмом и длительностью сессии. Владельцы 20 доменов в коде не названы. По [инструкции tg-ws-proxy](https://github.com/Flowseal/tg-ws-proxy/blob/main/docs/RU/CfProxy.md) такой домен настраивается в режиме SSL Flexible с записями `kws1`…`kws5` на адреса датацентров, а в [режиме Flexible Cloudflare подключается к серверу назначения по обычному HTTP](https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes/flexible/). Отрезок от Cloudflare до Telegram тогда идёт без TLS, защищённый только MTProto. Проще говоря: на запасных ступенях содержимое переписки по-прежнему недоступно никому, кроме устройства и Telegram, а вот факт подключения к Telegram, номер датацентра, объём и время видят Cloudflare, владелец домена или воркера и всё, что стоит между Cloudflare и Telegram. Для обхода блокировки это приемлемо, для скрытности — нет. ## Готовые сокеты и таймауты Android держит про запас по одному сокету на каждый маршрут, который уже прошёл TCP, TLS и апгрейд. Причина в том, что некоторые провайдеры теряют первый пакет нового соединения, и каждое новое подключение может стоить секунд. Запасной сокет начинает передачу сразу. Заголовок obfuscated2 в него ещё не отправлен, поэтому релей не привязал его ни к какому датацентру. Живёт такой сокет не дольше 70 секунд: 24 сентября 2026 года релей ещё отвечал после 90 секунд простоя и закрыл сокет к 110-й секунде. Для туннеля и подключений по имени из DNS запаса нет. Таймауты Android: 2,5 секунды на TCP, 8 секунд на TLS и апгрейд, 5,5 секунды на первый ответ MTProto, для медиа — 20 секунд, потому что на «холодный» файл сервер отвечает дольше. Desktop отдаёт таймауты сессии Telegram Desktop и добавляет свои минимумы: 4 секунды для доменов за Cloudflare и 6 секунд для туннеля. ## WSS, прокси и VPN Оба клиента считают WSS транспортом, а не прокси, и сочетают его с прокси по-разному. **Android.** Тумблер — «Настройки прокси» → раздел «Telegram WSS транспорт» → «Использовать WSS транспорт», включён по умолчанию. Выбранный прокси любого типа (SOCKS5, MTProxy, WEB-прокси) приостанавливает WSS, а не выключает: стоит выключить прокси, и клиент снова идёт через WSS. Активный VPN приостанавливает WSS всегда. Если выбранный прокси не подключается 15 секунд, клиент временно уходит на WSS, а прокси проверяет раз в 30 секунд; если прокси часто пропадает и возвращается, интервал растёт до 5 минут. В этот момент в шапке экрана прокси видна строка «Прокси недоступен, работаем через WSS Telegram». Пока WSS активен, клиент просит сервер отдавать файлы через свои датацентры, а не перенаправлять на CDN-адреса Telegram: у CDN нет веб-релеев. Одна деталь миграции: при обновлении флаг `wssProxyDecoupled` один раз принудительно включил WSS и тем, кто раньше выключил его сам. **Desktop.** Транспорт по умолчанию — WSS; с 1 октября 2026 года новая установка больше не добавляет локальный SOCKS5 `127.0.0.1:1353` и сразу ходит через встроенный транспорт ([коммит 567994f15b](https://git.zapret.moe/zastogram/ZaStoGram_desktop/commit/567994f15b0c24257fb784ab563e7589e1e60a7d)). WSS поверх удалённого SOCKS5 разрешён. С MTProxy и HTTP-прокси клиент переходит на обычный TCP. С локальным SOCKS5 (`localhost`, `127.x.x.x`, `::1` или порт 1353) WSS тоже выключается: заворачивать WebSocket в локальный мост, который сам строит WebSocket, бессмысленно. Если удалённый SOCKS5 оборвал WSS-соединение, WSS для этого прокси запрещается на 30 минут. Механизм ухода с недоступного прокси на WSS такой же, как на Android, с теми же 15 секундами и интервалами проверки. В Desktop есть и поля для своего релея: адрес, порт, путь и имя для SNI, для любого датацентра. Подписи к ним устарели: «empty = official DC2/DC4» и предупреждение «No certificate check is done — use only a relay you trust». На деле сертификат своего релея проверяется по указанному имени. Состояние транспорта Desktop показывает в «Настройки» → «Продвинутые настройки» → «Тип соединения»: строка вида `Default (WSS used, ping: 87 ms)`. Android такого индикатора не имеет; фактическое состояние видно только в диагностике при ошибке входа (`wss=on`, `suspended` или `off`) и в технических деталях сообщения. Звонки WSS не переносит ни в одном клиенте: голос и видео Telegram идут по UDP. В Android-клиенте для звонков есть отдельный экспериментальный пункт «Звонки через TCP/TLS»: он пробует релеи звонка по TCP и TLS, если UDP не заработал, но к WSS отношения не имеет. Как закрыть звонки пакетным обходом или VPN, — в [[mtproxy/telegram-wss-limits|заметке об ограничениях]]. ## Четыре реализации: мост снаружи или транспорт внутри Кроме двух клиентов ZaStoGram, тот же приём используют мосты: программы, которые работают рядом с любым клиентом Telegram, слушают локальный порт как прокси и сами строят WebSocket. Мосту приходится расшифровывать транспортную обёртку клиента и шифровать поток заново, потому что клиент шифрует его ключом из секрета прокси, а Telegram этого секрета не знает. Слой MTProto с ключом авторизации мост при этом не трогает. | | tg-ws-proxy | ZapretGUI, модуль `telegram_proxy` | ZaStoGram Android | ZaStoGram Desktop | |---|---|---|---|---| | Как подключается клиент | MTProxy на `127.0.0.1:1443` | MTProxy или SOCKS5 на `127.0.0.1:1353` | встроено | встроено | | Клиент Telegram | любой | любой | только этот | только этот | | Релеи Telegram по умолчанию | DC2, DC4 | DC1–DC5 (с 16.10.2026) | DC1–DC5 | DC1–DC5 | | Домены за Cloudflare | 20 встроенных, обновляются раз в час | 20 | 20 (те же) | 20 (те же) | | Воркер Cloudflare | свой, если указан | свой или 3 общих | 3 общих | 3 общих | | Что в конце | прямой TCP | внешний SOCKS5, иначе прямой TCP | снова домены | снова домены | [tg-ws-proxy от Flowseal](https://github.com/Flowseal/tg-ws-proxy) — мост на Python с приложением в системном трее. Режим входа у него один, MTProxy с секретом `dd` или FakeTLS-секретом `ee`; SOCKS5 в текущем коде нет. По умолчанию он держит по четыре готовых соединения на датацентр и для части попыток подставляет в TLS чужое имя `sprinthost.ru`, оставляя честное имя в заголовке `Host`. С версии 1.11.0 медиа через домены Cloudflare мультиплексируются по HTTP/2 в одно соединение; выключается это флагом `--no-h2`. Отсюда же ZaStoGram взял список из 20 доменов. Модуль `telegram_proxy` в [ZapretGUI](https://git.zapret.moe/zapretdiscordyoutube/zapretgui) повторяет лестницу ZaStoGram и использует те же три воркера, но заканчивает её иначе: внешними SOCKS5-серверами проекта, а прямой TCP идёт в ход, только если внешнего сервера нет. До 16 октября 2026 года он ходил на релей только для DC2 и DC4; с [коммита cb72426c](https://git.zapret.moe/zapretdiscordyoutube/zapretgui/commit/cb72426c8de4d15da363968845ea8725fad7656e) [каталог маршрутов модуля](https://git.zapret.moe/zapretdiscordyoutube/zapretgui/src/branch/main/src/telegram_proxy/proxy/route_catalog.py) — та же таблица адресов DC1–DC5, что в ZaStoGram, с двумя адресами у DC2/DC4. Главная разница двух подходов — в установке и в выборе клиента. Мост ставится отдельно и подходит к официальному Telegram, но добавляет промежуточное перешифрование и локальный порт. Встроенный транспорт ничего не требует от пользователя, кроме самого клиента, и не перешифровывает поток, но работает только в этом клиенте. ## Как узнать, что происходит у вас - [ ] Проверьте, открыт ли релей по TCP, а не `ping`: DPI режет соединения по порту и оставляет пинг живым. В Windows: `tnc 149.154.174.100 -Port 443`, строка `TcpTestSucceeded`. - [ ] В Desktop откройте «Тип соединения»: `WSS used` с пингом значит, что транспорт работает; «WSS unavailable for this DC. Add a proxy.» появляется, только когда для датацентра нет ни одной ступени. - [ ] В Android при ошибке входа посмотрите строку диагностики: `wss=suspended` означает, что WSS включён, но его приостановил прокси или VPN. - [ ] В журнале клиента ищите строки `wss_session`: поле `route=` показывает, по какой ступени шло соединение (`ip`, `dns`, `cdn`, `tunnel`). Если почти всё идёт через `tunnel`, медленные загрузки объясняются туннелем, а не сетью. - [ ] Если в вашей сети закрыты и релеи, и Cloudflare, WSS не поможет: нужен туннель через свой сервер — [[Zapret/mtproto/00-overview|MTProxy]] или VPN. Как понять, кто виноват, когда не подключается и MTProxy, — в [[mtproxy/faketls-relay-diagnosis|разборе диагностики]]. ## Что мы теперь знаем об архитектуре Telegram Разбор кода четырёх реализаций, журналов тестировщиков и замеров складывается в картину того, как устроена сторона Telegram. Ни одно из этих свойств не описано в документации: всё восстановлено по поведению серверов, и Telegram может изменить его в любой день. Но именно эти свойства объясняют, почему у WSS-транспорта столько тихих отказов. **Сервер молчит вместо того, чтобы сообщить об ошибке.** Релей не отвечает на первый кадр короче 64 байт и молча выбрасывает второй пакет в кадре. Явную ошибку, кадр `close` с текстом `404`, он присылает только на совсем короткий первый кадр. Для клиента тишина неотличима от блокировки у провайдера, поэтому каждая реализация находит эти правила заново, замерами, а не по документации. На этом в августе 2026 года споткнулись все четыре проекта. **Адреса входа устроены несогласованно.** На чужое имя три адреса отвечают тремя разными способами: `302` с подсказкой правильного имени, тишиной до таймаута или, как адрес DC5, настоящим ответом. Сертификаты на чужие имена тоже разные: `*.telegram.org` у адреса DC2/DC4 и `*.telesco.pe` у адреса DC1/DC3. У DC2/DC4 два рабочих адреса, но DNS называет только один из них. Клиенту приходится держать таблицу адресов, которой нет ни в одном официальном источнике, и откат на DNS на случай, если таблица устареет. **Веб-вход покрывает не всю инфраструктуру.** У DC203, из которого Telegram отдаёт медиа аккаунтам без Premium, веб-релея нет: имя `kws203.web.telegram.org` не существует. Нет веб-релеев и у CDN-серверов Telegram, на которые сервер сам перенаправляет загрузки популярных файлов. Поэтому клиент, который ходит только через веб-вход, должен отказываться от перенаправлений на CDN, как делает Android-клиент ZaStoGram, а до DC203 добираться окольными путями: через домены за Cloudflare или туннель. **У каждого датацентра два кластера ключей.** Обычные соединения и загрузки файлов обслуживают разные группы серверов, обычный и медийный кластер. Временный ключ, созданный в одном, второй не знает и отвечает ошибкой `-404`. Разные пути ведут в разные кластеры: домены за Cloudflare — в обычный (медийных имён `-1` у них нет), а релей `kwsN-1` и туннель — в медийный. Поэтому каждая смена маршрута стоила пользователю Desktop от 9 до 30 секунд без картинок, пока клиент не научился сбрасывать медийные ключи сразу ([коммит 92ea9c103e от 2 октября 2026 года](https://git.zapret.moe/zastogram/ZaStoGram_desktop/commit/92ea9c103e423e812dcde790c4f5c7daa8042504)). **Обфускация не скрывает ни датацентр, ни ключ.** Ключ obfuscated2 лежит в первых байтах того же потока, а номер ключа авторизации идёт в каждом пакете открыто. Любой, кто держит TLS-соединение, — Cloudflare, воркер, владелец домена — видит, к какому датацентру идёт клиент и под каким ключом. ZapretGUI на этом строит полезную функцию: запоминает, какой кластер принял ключ. Но то же самое может сделать и любой посредник. **Звонки живут вне MTProto.** Голос и видео идут по UDP к отдельным релеям звонков, адреса которых сервер выдаёт в момент звонка. Ни MTProxy, ни WSS их не несут, а в Desktop-клиенте поддержка прокси для звонков отключена в коде целиком. Подробнее — в [[mtproxy/telegram-wss-limits|заметке об ограничениях]]. **Вся инфраструктура сидит в нескольких компактных подсетях.** Датацентры, веб-вход и релеи — это `149.154.160.0/20`, несколько сетей `91.108.x.0/22` и пара соседних. Веб-вход Telegram живёт в тех же подсетях, что и обычные датацентры, поэтому его тоже можно закрыть по IP, и сообщения о таких блокировках уже есть. Отсюда и лестница запасных путей через чужую инфраструктуру: пока Telegram не даёт входов вне своих подсетей, обходить блокировку по адресам приходится через Cloudflare. ## Если пишете свою реализацию Сводка того, что подтверждено замерами и историей ZaStoGram: 1. Первый кадр — не короче 64 байт. Заведите буфер, который придерживает начальные байты, пока их меньше заголовка. 2. Один кадр — не больше одного MTProto-пакета. Запоминайте границы пакетов при постановке в очередь, а не после склейки. 3. Адрес входа выбирайте по датацентру, у DC2/DC4 держите оба адреса и переходите на второй до имени из DNS: закрытым может оказаться любой из них. 4. Имя в SNI и в `Host` — всегда `kwsN.web.telegram.org` или `kwsN-1.web.telegram.org`, даже при подключении по IP. Байты 60–61 для релея не заполняйте. 5. Считайте отказы по датацентру, по адресу и по сети отдельно, склеивайте всплески и не путайте потерю пакета с закрытым релеем. 6. Отдельно проверяйте создание ключа к новому датацентру: «переписка работает» этот случай не ловит, потому что переписка идёт через датацентр аккаунта. 7. Не давайте одной повторяющейся строке забить журнал: в августе 2026 года ошибка «нет ключа для датацентра» дала 98 926 записей за 61 секунду и вытеснила всю остальную диагностику. ## Чем WSS отличается от MTProxy и VPN [[Zapret/mtproto/00-overview|MTProxy]] — это сервер, свой или чужой, к которому клиент подключается и который дальше сам идёт к Telegram. Он позволяет менять адреса и прятаться за FakeTLS, но требует VPS, а его адрес рано или поздно попадает в списки блокировок. WSS ничего своего не требует: клиент идёт к Telegram через его же веб-вход, а при закрытом входе — через Cloudflare. Управлять точкой выхода при этом нельзя: если релей молчит, а лимит воркеров исчерпан, сделать с этим нечего. | | MTProxy на своём сервере | WSS-транспорт | VPN | |---|---|---|---| | Нужен свой сервер | да | нет | обычно да | | Куда идёт трафик | ваш сервер | Telegram, при закрытом релее — Cloudflare | ваш сервер | | Кто видит транспортный слой | вы | Telegram; на запасных ступенях — Cloudflare и владельцы доменов и воркеров | вы и провайдер VPN | | Работает вне Telegram | нет | нет | да | | Переносит звонки | нет | нет | да | Развитие той же идеи со своим сервером — [[tproxy/tproxy|WEB-прокси]]: там MTProto тоже едет внутри обычного веб-трафика, но к вашему домену, а не к веб-входу Telegram. ## Источники - [tg-ws-proxy (Flowseal): исходники и README](https://github.com/Flowseal/tg-ws-proxy) - [tg-ws-proxy: релизы, v1.11.2 от 11 октября 2026 года](https://github.com/Flowseal/tg-ws-proxy/releases) - [tg-ws-proxy: инструкция по своему домену за Cloudflare (режим Flexible, записи kws1…kws5)](https://github.com/Flowseal/tg-ws-proxy/blob/main/docs/RU/CfProxy.md) - [RFC 6455 — стандарт WebSocket](https://datatracker.ietf.org/doc/html/rfc6455) - [Cloudflare Workers: лимиты бесплатного тарифа, 100 000 запросов в сутки и ошибка 1027](https://developers.cloudflare.com/workers/platform/limits/) - [Cloudflare: режим SSL Flexible, подключение к серверу по HTTP](https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes/flexible/) - [ZaStoGram Android, коммит f22da13d2 от 8 августа 2026 года — первый кадр не короче 64 байт](https://git.zapret.moe/zastogram/ZaStoGram/commit/f22da13d2947207b64526492f5cbd46ae06571d9) - [ZaStoGram Android, коммит dadaf092d от 9 августа 2026 года — один пакет на кадр](https://git.zapret.moe/zastogram/ZaStoGram/commit/dadaf092def4d23efefb7e031616b46240c2bc6b) - [ZaStoGram Android, коммит 96c4549a4 от 9 августа 2026 года — откат на прямое соединение при закрытом релее](https://git.zapret.moe/zastogram/ZaStoGram/commit/96c4549a4d088521ab5515928f7acd0ee6f452c1) - [ZaStoGram Android, коммит f875caa03 от 27 августа 2026 года — сторож «чёрной дыры»](https://git.zapret.moe/zastogram/ZaStoGram/commit/f875caa033145ff2c103e0ca5a1e054d4d94f5ff) - [ZaStoGram Android, коммит 006cb614f от 27 сентября 2026 года — домены за Cloudflare](https://git.zapret.moe/zastogram/ZaStoGram/commit/006cb614fe844f7c49b8cfea108dcf061714a427) - [ZaStoGram Android, коммит af99f5b72 от 8 октября 2026 года — несколько воркеров вместо одного](https://git.zapret.moe/zastogram/ZaStoGram/commit/af99f5b7210ddcea0269443133bb4e8ac2f20c0c) - [ZaStoGram Desktop, коммит 7f3ceffb32 от 8 августа 2026 года — таблица адресов входа DC1–DC5](https://git.zapret.moe/zastogram/ZaStoGram_desktop/commit/7f3ceffb32397beb86fc58ed1a59f59eff0be4bd) - [ZaStoGram Desktop, коммит 567994f15b от 1 октября 2026 года — без локального SOCKS5 по умолчанию](https://git.zapret.moe/zastogram/ZaStoGram_desktop/commit/567994f15b0c24257fb784ab563e7589e1e60a7d) - [ZaStoGram Android, коммит f7159aabd от 16 октября 2026 года — два адреса входа у DC2/DC4](https://git.zapret.moe/zastogram/ZaStoGram/commit/f7159aabd3e62b76e711e3859ae604901a95b76e) - [ZaStoGram Desktop, коммит 4399dd9626 от 16 октября 2026 года — два адреса входа у DC2/DC4](https://git.zapret.moe/zastogram/ZaStoGram_desktop/commit/4399dd96261134065c7899a7d8c537ca64bcc462) - [ZapretGUI, коммит cb72426c от 16 октября 2026 года — релеи DC1–DC5 и два адреса у DC2/DC4](https://git.zapret.moe/zapretdiscordyoutube/zapretgui/commit/cb72426c8de4d15da363968845ea8725fad7656e) - [ZaStoGram Android, коммит 7c6cfb539 от 16 октября 2026 года — DC203 через домены за Cloudflare](https://git.zapret.moe/zastogram/ZaStoGram/commit/7c6cfb539c78444a4456a82a8a767bff9f0d7721) - [ZaStoGram Desktop, коммит 09fefd7e6e от 16 октября 2026 года — DC203 через домены за Cloudflare](https://git.zapret.moe/zastogram/ZaStoGram_desktop/commit/09fefd7e6eb2f5acb3e908fe5b9ef6590d6366f4) - [ZapretGUI, коммит 676f111c от 16 октября 2026 года — DC203 через домены за Cloudflare](https://git.zapret.moe/zapretdiscordyoutube/zapretgui/commit/676f111c37aa331fc9e340a79e5ce256db58dd99) - [ZaStoGram Desktop, коммит 92ea9c103e от 2 октября 2026 года — медийные ключи сбрасываются при смене маршрута](https://git.zapret.moe/zastogram/ZaStoGram_desktop/commit/92ea9c103e423e812dcde790c4f5c7daa8042504) - [tg-ws-proxy, issue #1450 от 14 октября 2026 года — пользователь сообщает о блокировке 149.154.167.220 по IP](https://github.com/Flowseal/tg-ws-proxy/issues/1450) - [ZapretGUI: исходники](https://git.zapret.moe/zapretdiscordyoutube/zapretgui) - [ZapretGUI: каталог маршрутов модуля telegram_proxy](https://git.zapret.moe/zapretdiscordyoutube/zapretgui/src/branch/main/src/telegram_proxy/proxy/route_catalog.py) ## 📚 См. также - [[mtproxy/telegram-wss-limits|Ограничения WSS: что не работает и почему]] — парная заметка: закрытые релеи, медиа и CDN, звонки, лимиты Cloudflare, типичные диагнозы - [[mtproxy/mtproxy|Раздел MTProxy]] — обзор всех заметок про MTProxy, WSS и WEB-прокси - [[premium/android|ZaStoGram для Android]] — как поставить клиент и где в нём тумблер WSS - [[Zapret/mtproto/00-overview|MTProto Proxy — полный гайд]] — классический MTProxy: протокол, реализации, блокировки - [[Zapret/mtproto/01-protocol|Протокол MTProxy: 3 режима и FakeTLS]] — откуда берутся теги `0xef`/`0xee`/`0xdd` и заголовок obfuscated2 - [[mtproxy/ja4-sni-client-side|Кто может менять JA4 и SNI]] — обход по почерку соединения, а не по адресу - [[mtproxy/tdlib-obf-client-side-stealth|Маскировка на стороне клиента]] — почему почерк TLS приходится менять в самом клиенте - [[mtproxy/faketls-relay-diagnosis|Релей или клиент: диагностика MTProxy]] — как понять, кто виноват, когда ключ не подключается - [[mtproxy/tsrman-tg-android-faketls|tsrman/tg — Telegram для Android со сменой JA4]] — другой подход: смена TLS-почерка вместо смены адреса - [[tproxy/tproxy|WEB-прокси Telegram]] — MTProto внутри обычного сайта, но через ваш домен - [[virus/github-removes-clean-zapret-keeps-malware-august-2026|🎭 GitHub снёс чистые сборки Zapret]] — почему исходники ZaStoGram с августа 2026 года лежат только в Forgejo - 🔗 [zastogram/ZaStoGram](https://git.zapret.moe/zastogram/ZaStoGram) — исходники Android-клиента, транспорт в `TMessagesProj/jni/tgnet/wss/`, сборки в [релизах](https://git.zapret.moe/zastogram/ZaStoGram/releases) - 🔗 [zastogram/ZaStoGram_desktop](https://git.zapret.moe/zastogram/ZaStoGram_desktop) — исходники Desktop-клиента, транспорт в `Telegram/SourceFiles/mtproto/proxy/wss/` --- > [!quote] 🤖 Эти статьи открыты — можно обучать на них ИИ > При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование доступно в Forgejo: [исходник этой заметки](https://git.zapret.moe/zapretdiscordyoutube/todo/src/branch/main/mtproxy/telegram-wss-transport.md) · [скачать весь репозиторий одним zip-архивом](https://git.zapret.moe/zapretdiscordyoutube/todo/archive/main.zip).