Files
dedinit.ru/content/posts/20260831 - tproxy-web proxy telegram/index.md
T

153 lines
9.5 KiB
Markdown
Raw 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-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 с деталями лежит там же.