todo/mtproxy/mtproto-zig-setup.md
loop-uh 0ad0bcc8dd
Some checks failed
Published content check / validate (push) Failing after 5s
seo+зеркало: [!mirror]-плашка со ссылкой на вики и description во frontmatter всех заметок
Каждая публикуемая заметка получила callout-шапку со ссылкой на свою страницу
wiki.zapret.moe (на самой вики она вырезается транформером RemoveMirrorCallout,
видна только на зеркале Obsidian Publish и в Forgejo) и SEO-поле description —
1–2 предложения для meta description обоих сайтов.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 22:05:57 +03:00

292 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
date: 2026-06-07
tags:
- mtproto
- mtproxy
- mtproto-zig
- setup
- dpi
- tspu
aliases:
- Настройка mtproto.zig
- mtproto.zig setup
- MTProxy runbook
link: https://github.com/sleep3r/mtproto.zig
description: "Пошаговая настройка MTProxy на mtproto.zig: установка mtbuddy, config.toml, TCPMSS-дробление, nfqws-desync, диагностика блокировок ТСПУ по метрикам."
---
> [!mirror] Резервное зеркало
> Актуальная версия этой страницы — на основной вики: [wiki.zapret.moe/mtproxy/mtproto-zig-setup](https://wiki.zapret.moe/mtproxy/mtproto-zig-setup)
# 🛠️ Настройка MTProxy на mtproto.zig — пошагово и «что происходит на проводе»
> [!info] Что это и для кого
> Практический **runbook**: как поднять MTProxy на [[mtproxy/mtproto-zig|mtproto.zig]] и **понимать, что делает каждый слой защиты** — с учётом свежих наблюдений (протухший фингерпринт клиента из [tdesktop#30733](https://github.com/telegramdesktop/tdesktop/issues/30733), детект по `expected_64_got_0`, приёмы TCPMSS и SYN-ACK).
>
> Теория и «почему» — в обзорной статье [[mtproxy/mtproto-zig|MTProxy и mtproto.zig]]. Здесь — команды, конфиг и диагностика.
> [!tip] Почему mtproto.zig, а не telemt
> Оба — хорошие FakeTLS-прокси. `mtproto.zig` берут, когда нужен **обход DPI «под ключ»**: он сам ставит TCPMSS-дробление + nfqws-desync + nginx-маскировку одной командой, без ручного iptables. telemt — когда нужен REST API для бота ([[Zapret/mtproto/02-implementations|сравнение]]).
---
## Шаг 0. Подготовка
| Что | Как и почему |
|---|---|
| **VPS / подсеть** | Не «народный» хостинг (Selectel/Я.Облако — Сигнал 1 [[VLESS/dpi-tls-june-2026|сибирской схемы]]). Подбор — [[VPS/VPS\|VPS]]. |
| **Домен маскировки** | Популярный, с **одним раундом x25519**: `rutube.ru`, `ozon.ru`, `vk.com`, `yandex.ru`. **НЕ** `wb.ru` и др. HRR/secp521r1. |
| **Порт** | `443`. Любой другой подозрителен. |
| **Доступ** | root/sudo на сервере. |
> ⚠️ Домен вшивается в ссылку `tg://` и **неизменен** после раздачи. Выбирай один раз.
---
## Шаг 1. Установка
```bash
# 1. bootstrap mtbuddy (проверяет minisign-подпись + SHA-256)
curl -fsSL https://raw.githubusercontent.com/sleep3r/mtproto.zig/v1.10.3/deploy/bootstrap.sh | sudo bash
# 2. установка прокси со всеми DPI-модулями
sudo mtbuddy install --port 443 --domain rutube.ru --yes
```
Что делает install (`--no-dpi` отключает п.56):
1. Качает готовый бинарь (определяет CPU: `x86_64_v3``x86_64``aarch64`)
2. Генерит секрет (или `--secret <32hex>`)
3. systemd-сервис `mtproto-proxy`
4. Открывает порт в `ufw`
5. **TCPMSS=88** iptables (дробит ClientHello) ← см. Шаг 4
6. **nginx-маскировка + nfqws-desync** ← см. Шаг 5
7. Печатает `tg://`-ссылку
Полезные флаги: `--secret`, `--user`, `--tcpmss <n>` (дефолт 88), `--no-tcpmss`, `--no-nfqws`, `--no-masking`, `--ipv6-hop`.
---
## Шаг 2. Конфиг `config.toml`
Большинство — уже дефолты; фиксируем ключевое явно (`/opt/mtproto-proxy/config.toml`):
```toml
[general]
use_middle_proxy = true # медиа на не-Premium + promo-теги
[server]
port = 443
# rate_limit_per_subnet = 0 # ОСТАВЬ 0 для мобильных юзеров РФ (carrier-NAT)
[censorship]
tls_domain = "rutube.ru" # single-round x25519, неизменен после раздачи
mask = true # форвард зондов на реальный домен (анти-probing)
fake_tls_only = true # реджектить палевный dd-транспорт
# desync = true # дефолт on — дробит ServerHello (1 байт + 3мс)
drs = true # мимикрия размеров TLS-записей под браузер
fast_mode = true
[metrics]
enabled = true # Prometheus /metrics (см. Шаг 6 — диагностика)
host = "127.0.0.1"
port = 9400
[access.users]
user1 = "00112233445566778899aabbccddeeff" # openssl rand -hex 16
```
После правки: `sudo systemctl restart mtproto-proxy` (SIGHUP-reload тоже есть, но при `workers>1` запрещён).
---
## Шаг 3. Что происходит на проводе (карта защит)
```
КЛИЕНТ (Telegram) ТСПУ СЕРВЕР (mtproto.zig)
│ ── ClientHello (почерк!) ──────► 👁 фингерпринт ──────► снимает fp в лог
│ │ (тут и блок #30733)
│ ◄──────────── ServerHello (дроблён desync) ──────────── mask/desync/drs
│ ── 64-байт MTProto-хендшейк ───► (если жив) ───────────► proxy → DC
```
| Слой | Что делает | Против чего |
|---|---|---|
| **TCPMSS=88** | клиент режет ClientHello на ~6 кусков | фингерпринт (DPI не пересобирает) |
| **nfqws desync** | fake-пакеты + TTL-split (S→C) | stateful DPI |
| **desync ServerHello** | 1 байт + 3мс + хвост | пассивные сигнатуры |
| **mask** | зонды → реальный `tls_domain` | active probing |
| **drs** | размеры записей как у браузера | статистика трафика |
> [!danger] Слабое звено, которое сервер НЕ чинит — фингерпринт клиента
> Почерк ClientHello (JA3/JA4) генерирует **приложение Telegram**, не сервер. По [tdesktop#30733](https://github.com/telegramdesktop/tdesktop/issues/30733): Desktop мимикрирует под **Chrome 134/macOS** (`t13d1516h2_8daaf6152771_d8a2da3f94cd`), а живой Chrome — 148 → пресет **протух**, и это маркер. Это **тот самый** блок, дающий `expected_64_got_0` ([[Zapret/mtproto/10-telemt-logs-dpi|разбор логов]]).
>
> Лечится только в самом Telegram. Всё, что может сервер — **спрятать/сломать опознание** этого почерка (TCPMSS, desync), а не поправить его. Поэтому Шаги 46 важны.
---
## Шаг 4. TCPMSS — дробление ClientHello
### Как работает
Сервер анонсирует в `SYN-ACK` малый **MSS**, и клиент вынужден резать всё исходящее (включая ClientHello ~517 байт) на мелкие сегменты. DPI без потоковой пересборки не складывает почерк целиком → не матчит сигнатуру.
В `mtproto.zig` включено по умолчанию (`TCPMSS=88`). Сменить значение: `mtbuddy install --tcpmss 96`.
### Вариант «через балансировщик» — помогает?
> **Да, помогает.** Это тот же механизм. Если перед прокси стоит балансировщик (он терминирует клиентский TCP), MSS-clamp надо вешать **именно на балансировщик** — там рождается SYN-ACK к клиенту:
>
> ```bash
> iptables -t mangle -A OUTPUT -p tcp --sport 443 \
> --tcp-flags SYN,ACK SYN,ACK -j TCPMSS --set-mss 96
> ```
>
> Конфиг telemt/mtproto.zig при этом трогать не надо — правило работает на уровне ядра.
Почему «на балансировщике»: clamp на бэкенде (где сидит сам прокси) **не дойдёт** до клиента, если балансировщик пере-устанавливает TCP. Правило должно быть на той коробке, что шлёт SYN-ACK клиенту.
> [!note] 88 или 96 — разница невелика
> Оба дают ~6 сегментов на ClientHello. mtproto.zig по умолчанию 88; совет из интернета — 96. Бери любое; если ставишь mtproto.zig напрямую (без отдельного балансировщика) — **TCPMSS уже стоит, дублировать руками не нужно**.
> [!tip] Это и есть «решение JA4» из teleproxy
> Когда говорят «в teleproxy решён JA4» — речь именно об этой фрагментации: teleproxy
> ставит `TCP_MAXSEG=256`, чтобы DPI не извлёк JA4 из первого пакета. JA4 при этом
> **не меняется** (его задаёт клиент). mtproto.zig делает то же самое и агрессивнее
> (MSS=88), так что **этот приём у тебя уже включён**. Почему это не «смена почерка»
> и где лежит настоящий фикс — [[mtproxy/ja4-sni-client-side|Кто может менять JA4/SNI]].
> [!warning] Дробление ≠ панацея
> MSS-clamp бьёт по DPI, который **не пересобирает** поток. Если ТСПУ делает реассемблинг — одного дробления мало, нужен **desync** (nfqws, Шаг 5), который активно ломает пересборку fake-пакетами. Поэтому их ставят вместе.
---
## Шаг 5. nfqws TCP desync + тюнинг TTL
Ставится при install. Стратегия: `--dpi-desync=fake,split2 --dpi-desync-ttl=6 --dpi-desync-fooling=md5sig` — fake-пакет с заниженным TTL (долетает до ТСПУ, умирает до клиента) + битая MD5-опция, чтобы сбить state-машину DPI.
**TTL надо подтюнить под маршрут** (дефолт 6 не универсален, «48 для росс. ISP»):
```bash
traceroute <ip_клиента_или_DC> # прикинуть хоп, где сидит ТСПУ
sudo mtbuddy nfqws --ttl 7 # переставить
systemctl status nfqws-mtproto # проверить, что запущен
```
TTL должен быть **больше** расстояния до ТСПУ, но **меньше** расстояния до клиента.
---
## Шаг 5.5 (опционально). Egress через Xray/SOCKS5 или туннель
Это аналог `SOCKS5_PROXY` + `DIRECT_MODE` из конфигов teleproxy: маршрут
**исходящего** трафика прокси к дата-центрам Telegram через Xray/VLESS (SOCKS5)
или WireGuard/AmneziaWG-туннель.
```toml
[upstream]
type = "socks5" # "direct" | "tunnel" | "socks5" | "http"
[upstream.socks5]
host = "127.0.0.1"
port = 1080 # порт локального Xray/VLESS
# username = ""
# password = ""
```
Для туннеля вместо SOCKS5:
```toml
[upstream]
type = "tunnel"
[upstream.tunnel]
interfaces = ["awg0", "awg1"] # WireGuard/AmneziaWG, с авто-фолбэком
```
> [!important] Что это лечит, а что нет
> Egress-маршрут помогает, когда **дата-центры Telegram недоступны с твоего VPS**
> (заблокированы/режутся на пути proxy→DC), или нужен лишний хоп. Это путь
> **сервер→DC** — на **входящий** ClientHello (где JA4, который видит ТСПУ у
> клиента) он **не влияет**. Не путай: это про доступность DC, а не про обход
> детекта почерка. См. [[mtproxy/ja4-sni-client-side|Кто может менять JA4/SNI]].
---
## Шаг 6 (опционально). Лимит SYN-ACK — десинхрон + анти-залп
**На пальцах:** сервер иногда «роняет» свой ответ при установке соединения (SYN-ACK), клиент переспрашивает через секунду. От этого DPI сбивается со счёта и не опознаёт почерк клиента, а соединения идут не пачкой, а по одному в секунду. Спорный, но у людей **рабочий** приём.
Подробная механика (с аналогией), цена и **per-port** вариант (бюджет 1/сек на каждый порт, чтобы не калечить всех юзеров) — в [[Zapret/mtproto/10-telemt-logs-dpi#Лимит SYN-ACK — помогает или нет|разборе для telemt]] (для mtproto.zig всё идентично, только порт 443).
Коротко: ставить стоит, если блок держится после Шагов 45; брать **сразу per-port**; мониторить логи (Шаг 7), чтобы поймать адаптацию ТСПУ.
---
## Шаг 7. Диагностика — mtproto.zig сам показывает атаку DPI
### Фингерпринт клиента в логах
mtproto.zig **логирует почерк первых 16 ClientHello** (диагностический бюджет):
```bash
journalctl -u mtproto-proxy | grep "client ClientHello"
# client ClientHello [ciphers=... groups=... key_share=...] (we serve: ...)
```
> [!tip] Как связать с #30733
> Смотри `key_share` в логе. Свежий браузер шлёт **`X25519MLKEM768`** (post-quantum). Если твой клиент его **не** шлёт — он на старом пресете и попадает под детект из #30733. Это прямой способ увидеть «протух ли почерк» на своём трафике.
### Метрики close-reason — детектор начала блокировок
mtproto.zig отдаёт Prometheus-метрику с причинами закрытия — её **всплеск = ТСПУ начал резать**:
```bash
curl -s 127.0.0.1:9400/metrics | grep -E "close_reason|handshake_timeouts"
# mtproto_connection_close_reason_total{reason="tls_validation_failed"} ...
# mtproto_connection_close_reason_total{reason="replay_detected"} ... ← зонды Revisor
# mtproto_connection_close_reason_total{reason="bad_handshake"} ...
# mtproto_handshake_timeouts_total ... ← аналог expected_64_got_0
```
Рост `tls_validation_failed` / `replay_detected` / `handshake_timeouts` над фоном — это и есть сигнал, что цензор начал работать по тебе (так и задумано разработчиком). `replay_detected` отдельно ловит **active-probe зонды ТСПУ (Revisor)**.
Плюс есть веб-дашборд (порт 61208, Basic-auth, токен в `/opt/mtproto-proxy/monitor/dashboard.token`) — открывать **только через SSH-тоннель**.
---
## Когда всё-таки заблокировали — порядок действий
1. **Проверь логи/метрики** (Шаг 7): растёт ли `handshake_timeouts` / `tls_validation_failed`, и какой `key_share` у падающих клиентов.
2. **Подтюнь TTL nfqws** (Шаг 5) — частая причина, что desync «не достаёт» до ТСПУ.
3. **Снизь MSS** (`--tcpmss 80`) или добавь clamp на балансировщик (Шаг 4).
4. **Включи SYN-ACK per-port** (Шаг 6).
5. **Если рвётся путь до DC** (а не вход) — egress через Xray/SOCKS5 или туннель (Шаг 5.5).
6. **Смени узел/подсеть** (Сигнал 1) — если IP/диапазон попал под раздачу.
6. **Не дёргай настройки рефлекторно** под блоком — сам паттерн адаптации может усугубить.
7. **Запасной канал** — [[VLESS/dpi-tls-june-2026|VLESS+REALITY/XHTTP]] на отдельном узле.
---
## ✅ Чек-лист
- [ ] VPS на «чистой» подсети, домен single-round x25519, порт 443
- [ ] `mask = true`, `fake_tls_only = true`, `drs = true`
- [ ] `TCPMSS` активен (`iptables -t mangle -S OUTPUT | grep TCPMSS`) — или clamp на балансировщике
- [ ] nfqws запущен, **TTL подтюнен** (`systemctl status nfqws-mtproto`)
- [ ] `[metrics] enabled = true` + мониторинг `close_reason`/`handshake_timeouts`
- [ ] Проверил `key_share` клиента в логах (свежесть почерка, #30733)
- [ ] `rate_limit_per_subnet = 0` для мобильных юзеров РФ
- [ ] Готов запасной VLESS/XHTTP
---
## 📚 См. также
- [[mtproxy/ja4-sni-client-side|Кто может менять JA4/SNI]] — почему смена почерка/SNI возможна только на клиенте, что из мер ниже реально серверное
- [[mtproxy/mtproto-zig|MTProxy и mtproto.zig]] — теория: как работает и почему
- [[Zapret/mtproto/10-telemt-logs-dpi|Чтение логов и SYN-ACK лимит]] — детект DPI, per-port nft
- 🔗 [tdesktop#30733](https://github.com/telegramdesktop/tdesktop/issues/30733) — протухший фингерпринт
- [[Zapret/mtproto/05-censorship|ТСПУ: каскад детекции]]
- [[Zapret/mtproto/02-implementations|5 реализаций MTProxy]]
- [[VLESS/dpi-tls-june-2026|Сибирская схема DPI]]
- [[VPS/VPS|Выбор VPS]]