--- date: '2026-08-31T03:00:00+03:00' lastmod: '2026-08-31T03:00:00+03:00' draft: false title: 'WEB Proxy для Telegram Desktop: ставим tproxy-server на свой VPS и чиним грабли установщика' slug: 'tproxy-web-proxy-telegram-desktop' description: 'Рассказываю, как развернул WEB Proxy для Telegram Desktop на собственном VPS (tproxy-server + Caddy + MTProxy), что нашёл в установщике upstream и как починил падение mtproxy.service с правами на бинарь после сборки.' categories: - 'DevOps' - 'Networking' tags: - 'telegram' - 'proxy' - 'tproxy' - 'mtproto' - 'caddy' - 'vps' - 'hostkey' - 'debian' keywords: - 'telegram desktop' - 'web proxy' - 'tproxy-server' - 'MTProxy' - 'Caddy' - 'mount proxy telegram' - '203/EXEC' - 'systemd' - 'Hostkey' - 'vps03.nixg.ru' cover: image: "hero.svg" alt: "WEB Proxy для Telegram Desktop: Caddy, tproxy-server, MTProxy" --- # WEB Proxy для Telegram Desktop на своём VPS В моей инфраструктуре давно крутится Telegram-трафик через SOCKS5-туннель на VPS — но у этого подхода есть минусы: SOCKS5 легко режется DPI, а клиент надо настраивать отдельно. Альтернатива от самих разработчиков Telegram Desktop — **WEB Proxy**: прокси, который маскируется под обычный HTTPS-сайт на 443-м порту. Такой трафик не отличить от обычного захода на сайт, а подключение настраивается в два поля в настройках клиента. В этой статье — как я развернул [tproxy-server](https://github.com/telegramdesktop/tproxy-server) на свежем VPS (Debian 13, Hostkey), какие проблемы встретил в установщике и как их обошёл. Полезно всем, кто решит поднять свой WEB Proxy. ## Зачем WEB Proxy, а не SOCKS5 | Критерий | SOCKS5-туннель | WEB Proxy (tproxy-server) | |---|---|---| | Внешний вид трафика | SOCKS5 (легко детектится) | Обычный HTTPS на 443 | | Маскировка под сайт | нет | да (свой статический сайт) | | Настройка в Telegram Desktop | тип прокси + адрес + порт | hostname + secret | | Держит сам Telegram | да | да (через MTProxy на бэкенде) | Схема работы tproxy-server: ``` Telegram Desktop → HTTPS:443 → Caddy → tproxy-server:8080 → MTProxy:2398 → Telegram └ admin :8081 (/readyz, /healthz) ``` Caddy отдаёт Let's Encrypt сертификат и проксирует весь трафик на tproxy-server, который сам решает: обычные запросы отдаёт сайт-маскировку, а запросы WEB Proxy — гонит в MTProxy. Снаружи это просто HTTPS-сайт. ## Установка: что делает install.sh У upstream отличный установщик — `deploy/install.sh` делает почти всё сам: - ставит пакеты (ca-certificates, curl, nftables); - ставит **Caddy 2.11.4** и **Go 1.26.5** (если нет); - собирает `tproxy-server` из исходников; - собирает **MTProxy** (pinned commit `f36d8af`) в `/opt/MTProxy`; - создаёт systemd-сервисы: `tproxy-server`, `mtproxy`, `tproxy-firewall`, `caddy`; - настраивает таймер `refresh-mtproxy-config` (обновление списка серверов Telegram раз в сутки); - поднимает nft-правило, закрывающее порты MTProxy (2398, 8888) от внешнего мира. Запуск: ```bash ./deploy/install.sh --hostname vps03.nixg.ru \ --email me@example.com --site-dir /tmp/tproxy-site \ --secret "$(cat /tmp/tproxy-secret.txt)" ``` `--secret` — 32 hex-символа (`openssl rand -hex 16`), `--site-dir` — каталог со статическим сайтом-маскировкой. ## Грабли №1: mtproxy.service падает с 203/EXEC, readyz 503 После первого прогона установщика `tproxy-server` был active, Caddy слушал 80/443, но прокси не работал: ```text ● mtproxy.service - failed (Result: exit-code), status=203/EXEC ``` Порт 2398 не слушался, а `/readyz` административного эндпоинта отдавал 503 (readyz — это «вся цепочка готова», healthz при этом был 200). Причина оказалась в **правах на бинарь после сборки**. Установщик собирает MTProxy в `/opt/MTProxy/objs/bin/mtproto-proxy`, но из-за umask бинарь и каталоги получают права `700 root:root`. Юнит `mtproxy.service` запускается от пользователя `mtproxy` (с `NoNewPrivileges=true` и `ProtectSystem=strict`) — процесс не может прочитать бинарь и умирает с 203/EXEC. Лечится одной серией команд: ```bash chmod 755 /opt/MTProxy /opt/MTProxy/objs /opt/MTProxy/objs/bin chown root:mtproxy /opt/MTProxy/objs/bin/mtproto-proxy chmod 750 /opt/MTProxy/objs/bin/mtproto-proxy systemctl restart mtproxy ``` После этого `mtproxy` — active (running), слушает `0.0.0.0:2398`, readyz → 200. ## Грабли №2: флейк go test в установщике Первый прогон install.sh (холодный кэш Go, сборка всех пакетов параллельно) упал на тестах: ```text FAIL: internal/config — TestLoadAcceptsSystemdCredentialReadPermissions: group/other-readable profiles file outside a credential directory was accepted ``` А повторный `go test ./...` (тёплый кэш) — PASS. Это классическая гонка при холодном параллельном прогоне тестов, а не баг кода. Лечение простое: перезапустить install.sh — дальше идёт нормально. ## Грабли №3: «не открыты порты 80/443» — ложная тревога Снаружи curl на 80/443 не отвечал, и я заподозрил firewall провайдера (Hostkey). Пошёл в панель — а там **вообще нет настроек firewall/прокси**. Полез в документацию, искал API... На самом деле всё проще: порты у провайдера открыты по умолчанию, просто на 80/443 **ничего не слушало** — curl получал connection refused. Проверка: поднимаю временный `python3 -m http.server 80` → TCP connect снаружи OK. После установки Caddy сам слушает 80/443. Так что если у вас после установки снаружи не открывается сайт — сначала проверьте, что порт слушается (`ss -tlnp`), а не ищите firewall в панели провайдера. ## Проверка после установки ```bash systemctl status tproxy-server mtproxy tproxy-firewall caddy # все active curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8081/readyz # 200 curl -s -o /dev/null -w '%{http_code}' https://vps03.nixg.ru/ # 200 (сайт) openssl s_client -connect vps03.nixg.ru:443 -servername vps03.nixg.ru # LE-серт ss -tlnp | grep -E ':80 |:443|:2398|:8080|:8081' nft list ruleset | grep -E '2398|8888' # закрыто от внешнего мира ``` Наружу видны только 80/443. MTProxy-бэкенд (2398, 8888) закрыт nft — `iifname != "lo" ... drop`, то есть бэкенд не светится и не принимает подключения напрямую. ## Настройка клиента В Telegram Desktop: **Settings → Advanced → Connection Type → Use custom proxy → NEW PROXY → WEB Proxy**: - hostname: `vps03.nixg.ru` - secret: (32 hex-символа, которые вы сгенерировали) ## Итог WEB Proxy — отличная замена SOCKS5-туннелю, если нужна маскировка под обычный HTTPS: настраивается в два поля, трафик неотличим от сайта, а готовый установщик upstream делает почти всю работу. Главные грабли — права на бинарь MTProxy после сборки (203/EXEC) и ложная тревога с «закрытыми портами». Оба решаются за пару минут, если знать, куда смотреть. Полный набор файлов (заметки, сайт-маскировку, команду установки) я сложил в репозиторий [tproxy-web](https://github.com/telegramdesktop/tproxy-server) — точнее, в свой [tproxy-web на gitverse](https://gitverse.ru/kpa39l/tproxy-web), а INSTALL_NOTES.md с деталями лежит там же.