mirror of
https://gitverse.ru/kpa39l/telegram-web-proxy.git
synced 2026-09-29 09:15:02 +00:00
Initial commit: Hermes skill telegram-web-proxy
This commit is contained in:
@@ -0,0 +1,150 @@
|
|||||||
|
---
|
||||||
|
name: telegram-web-proxy
|
||||||
|
description: >-
|
||||||
|
Deploy Telegram Desktop WEB Proxy (tproxy-server) on a VPS.
|
||||||
|
category: devops
|
||||||
|
tags:
|
||||||
|
- telegram
|
||||||
|
- web-proxy
|
||||||
|
- tproxy
|
||||||
|
- mtproto
|
||||||
|
- caddy
|
||||||
|
- dpi
|
||||||
|
---
|
||||||
|
|
||||||
|
# Telegram WEB Proxy (tproxy-server)
|
||||||
|
|
||||||
|
## When to Use This Skill
|
||||||
|
|
||||||
|
Use when you need to:
|
||||||
|
|
||||||
|
- Развернуть **WEB Proxy для Telegram Desktop** (telegramdesktop/tproxy-server)
|
||||||
|
на VPS — маскируется под обычный HTTPS-сайт на 443, настраивается в Telegram
|
||||||
|
Desktop как WEB Proxy (hostname + secret)
|
||||||
|
- Починить `mtproxy.service` после установки (203/EXEC, readyz 503)
|
||||||
|
- Добавить ещё один секрет/профиль (мульти-секреты)
|
||||||
|
- Понять, почему «снаружи не открываются порты 80/443» после установки
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
TD → HTTPS:443 → Caddy → tproxy-server:8080 → MTProxy:2398 → Telegram
|
||||||
|
└ admin :8081 (/readyz, /healthz)
|
||||||
|
```
|
||||||
|
|
||||||
|
- Caddy отдаёт Let's Encrypt сертификат (tls-alpn) и проксирует ВЕСЬ трафик на
|
||||||
|
tproxy-server (127.0.0.1:8080). tproxy-server сам различает: обычные запросы →
|
||||||
|
сайт-маскировку (`public_dir`), запросы WEB Proxy → MTProxy.
|
||||||
|
- Снаружи это просто HTTPS-сайт; наружу открыты только 80/443.
|
||||||
|
- nft-правило (`tproxy-firewall`) закрывает MTProxy-бэкенд 2398/8888 от внешнего
|
||||||
|
мира: `iifname != "lo" tcp dport {2398, 8888} drop`.
|
||||||
|
|
||||||
|
## Deploy
|
||||||
|
|
||||||
|
1. Склонировать upstream: `git clone https://github.com/telegramdesktop/tproxy-server.git`
|
||||||
|
2. Подготовить сайт-маскировку (каталог со статическим `index.html`; нейтральный,
|
||||||
|
БЕЗ упоминаний Telegram) и secret: `openssl rand -hex 16` (32 hex).
|
||||||
|
3. Загрузить на сервер (rsync, либо tar+ssh — см. грабли #4).
|
||||||
|
4. Запустить:
|
||||||
|
```bash
|
||||||
|
./deploy/install.sh --hostname HOST --email ME@EXAMPLE.COM \
|
||||||
|
--site-dir /tmp/tproxy-site --secret "$(cat /tmp/tproxy-secret.txt)"
|
||||||
|
```
|
||||||
|
Ставит: ca-certificates curl nftables, Caddy 2.11.4, Go 1.26.5, собирает
|
||||||
|
tproxy-server, MTProxy (pinned commit), создаёт systemd-сервисы:
|
||||||
|
`tproxy-server`, `mtproxy`, `tproxy-firewall`, `caddy`, таймер
|
||||||
|
`refresh-mtproxy-config` (daily, обновляет список IP Telegram в proxy-multi.conf).
|
||||||
|
|
||||||
|
5. Проверка:
|
||||||
|
```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://HOST/ # 200 (сайт)
|
||||||
|
nft list ruleset | grep -E '2398|8888' # drop для не-loopback
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pitfalls
|
||||||
|
|
||||||
|
### 1. mtproxy.service → 203/EXEC (readyz 503)
|
||||||
|
|
||||||
|
**Симптом:** tproxy-server active, но `mtproxy` failed (203/EXEC), порт 2398 не
|
||||||
|
слушается, `/readyz` → 503 (healthz при этом 200).
|
||||||
|
|
||||||
|
**Причина:** install.sh собирает MTProxy в `/opt/MTProxy/objs/bin/mtproto-proxy`,
|
||||||
|
но umask даёт бинарю и каталогам `700 root:root`. Юнит `mtproxy.service`
|
||||||
|
запускается от пользователя `mtproxy` (NoNewPrivileges, 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
|
||||||
|
# → active (running), слушает 0.0.0.0:2398, readyz → 200
|
||||||
|
```
|
||||||
|
|
||||||
|
Повторный запуск install.sh безопасен (идемпотентен).
|
||||||
|
|
||||||
|
### 2. Флейк `go test ./...` внутри install.sh
|
||||||
|
|
||||||
|
Первый прогон (холодный кэш Go, параллельная сборка) может упасть на
|
||||||
|
`internal/config: TestLoadAcceptsSystemdCredentialReadPermissions`. Повторный —
|
||||||
|
PASS. Это гонка при холодном прогоне, не баг кода. Лечение: перезапустить
|
||||||
|
install.sh.
|
||||||
|
|
||||||
|
### 3. «Порты 80/443 закрыты снаружи» — ложная тревога
|
||||||
|
|
||||||
|
Если после установки curl снаружи не отвечает: сначала `ss -tlnp` на сервере.
|
||||||
|
Чаще всего на порту просто НИЧЕГО не слушает (curl = connection refused), а
|
||||||
|
firewall провайдера ни при чём. Проверка: поднять временный слушатель
|
||||||
|
(`python3 -m http.server 80`) и проверить TCP connect снаружи. У Hostkey
|
||||||
|
отдельного firewall в панели НЕТ — порты открыты по умолчанию; настройки
|
||||||
|
«прокси/фаервол» в панели искать не нужно.
|
||||||
|
|
||||||
|
Различать: `timeout` = режется (firewall/DPI), `refused` = нет слушателя.
|
||||||
|
|
||||||
|
### 4. rsync отсутствует на Debian minimal
|
||||||
|
|
||||||
|
Если на сервере нет rsync, грузить дерево tar+ssh:
|
||||||
|
```bash
|
||||||
|
tar czf - tproxy-server/ | ssh root@HOST 'mkdir -p /tmp/tproxy-server && tar xzf - -C /tmp'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Multi-profile secrets (несколько секретов)
|
||||||
|
|
||||||
|
Поддерживается: `/etc/tproxy-server/profiles.json` — **массив** профилей, у
|
||||||
|
каждого свой `secret`. Лимит `max_profiles: 32` (в config.json). Все профили по
|
||||||
|
умолчанию ведут в один MTProxy-бэкенд (127.0.0.1:2398).
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"profiles":[
|
||||||
|
{"name":"default","secret":"<hex32>","backend":"127.0.0.1:2398"},
|
||||||
|
{"name":"second","secret":"<hex32>","backend":"127.0.0.1:2398"}
|
||||||
|
]}
|
||||||
|
```
|
||||||
|
|
||||||
|
- systemd читает через `LoadCredential=profiles.json:/etc/tproxy-server/profiles.json`
|
||||||
|
**при старте** → после правки `systemctl restart tproxy-server`.
|
||||||
|
- Права файла должны быть 600 root (иначе Load откажет — тот самый
|
||||||
|
`TestLoadAcceptsSystemdCredentialReadPermissions`).
|
||||||
|
- Формат секрета: 16 байт = 32 hex (обычный), либо 17 байт с префиксом `dd`
|
||||||
|
(fake-TLS/DD режим). `openssl rand -hex 16` — обычный 32-hex, для Telegram
|
||||||
|
Desktop WEB Proxy это нужно.
|
||||||
|
|
||||||
|
## Client setup
|
||||||
|
|
||||||
|
Telegram Desktop → Settings → Advanced → Connection Type → Use custom proxy →
|
||||||
|
NEW PROXY → WEB Proxy: hostname + secret (32 hex).
|
||||||
|
|
||||||
|
Ссылка для шаринга не `t.me/proxy?...` (это MTProto-ссылка), а передаётся полями
|
||||||
|
(hostname/secret) — WEB Proxy не имеет share-ссылки вида `t.me/proxy`.
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- `mtproto-proxy` — классический MTProto proxy через Docker (seriyps), секреты с
|
||||||
|
`ee` (Fake TLS), ссылки `t.me/proxy`. Другой тип прокси.
|
||||||
|
- `networking-proxy` — umbrella по DPI-обходу (XRay, AmneziaWG, Shadowsocks, NNTP,
|
||||||
|
SSH-туннели).
|
||||||
|
- INSTALL_NOTES.md в репозитории `tproxy-web` (gitverse kpa39l) — полный опыт
|
||||||
|
установки 2026-08-31.
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
# tproxy-server — детали установки 2026-08-31 (VPS03, Hostkey)
|
||||||
|
|
||||||
|
Полный опыт развёртывания telegramdesktop/tproxy-server на Debian 13
|
||||||
|
(77.67.89.154, vps03.nixg.ru). Резюме в SKILL.md; здесь — команды и транскрипты.
|
||||||
|
|
||||||
|
## Установка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Clone upstream (локально, потом tar+ssh на сервер — rsync отсутствует)
|
||||||
|
git clone --depth 1 https://github.com/telegramdesktop/tproxy-server.git
|
||||||
|
|
||||||
|
# 2. Secret
|
||||||
|
openssl rand -hex 16 > /tmp/tproxy-secret.txt # 32 hex, chmod 600
|
||||||
|
|
||||||
|
# 3. Сайт-маскировка — /tmp/tproxy-site/index.html
|
||||||
|
# НЕЙТРАЛЬНАЯ страница ("личная страница"), без слова Telegram и сигнатур.
|
||||||
|
|
||||||
|
# 4. install.sh
|
||||||
|
./deploy/install.sh --hostname vps03.nixg.ru --email kpa39l@yandex.ru \
|
||||||
|
--site-dir /tmp/tproxy-site --secret "$(cat /tmp/tproxy-secret.txt)"
|
||||||
|
```
|
||||||
|
|
||||||
|
install.sh (v.2026) ставит: ca-certificates, curl, nftables; Caddy 2.11.4
|
||||||
|
(бинарник с GitHub); Go 1.26.5 (/opt/go*); собирает tproxy-server → /usr/local/bin;
|
||||||
|
MTProxy (pinned commit f36d8af) → /opt/MTProxy; systemd: tproxy-server, mtproxy,
|
||||||
|
tproxy-firewall, caddy; таймер refresh-mtproxy-config (daily).
|
||||||
|
|
||||||
|
## Схема сервисов
|
||||||
|
|
||||||
|
- tproxy-server: `ExecStart=/usr/local/bin/tproxy-server -config /etc/tproxy-server/config.json`,
|
||||||
|
`LoadCredential=profiles.json:/etc/tproxy-server/profiles.json`
|
||||||
|
- listen 127.0.0.1:8080 (relay), admin 127.0.0.1:8081 (/readyz /healthz)
|
||||||
|
- mtproxy: пользователь `mtproxy`, ExecStart=/opt/MTProxy/objs/bin/mtproto-proxy ...
|
||||||
|
- firewall (nft): `iifname != "lo" tcp dport {2398,8888} drop` — бэкенд закрыт
|
||||||
|
от внешнего мира, наружу только 80/443.
|
||||||
|
|
||||||
|
## Диагностика «не открыты порты» (важно!)
|
||||||
|
|
||||||
|
Симптом: `curl http://HOST/` и `https://HOST/` снаружи не отвечают (fail), хотя
|
||||||
|
локально порты слушаются (python3 http.server на :80 отвечает). Подозрение на
|
||||||
|
firewall провайдера (Hostkey) — в панели настроек firewall НЕТ.
|
||||||
|
|
||||||
|
Правда: порты у Hostkey открыты по умолчанию, firewall нет. curl не отвечал,
|
||||||
|
потому что на 80/443 НИЧЕГО не слушало (refused). Точная проверка — различить:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# снаружи (другая машина):
|
||||||
|
timeout 8 bash -c 'cat < /dev/null > /dev/tcp/HOST/80 && echo OPEN || echo "rc=$?"'
|
||||||
|
# refused → нет слушателя (нормально, лечится установкой)
|
||||||
|
# timeout → firewall/DPI режет
|
||||||
|
```
|
||||||
|
|
||||||
|
## Грабли mtproxy 203/EXEC
|
||||||
|
|
||||||
|
После install.sh: `systemctl status mtproxy` → failed, status=203/EXEC; readyz 503,
|
||||||
|
healthz 200, порт 2398 не слушается. Причина: umask даёт `/opt/MTProxy/objs/bin`
|
||||||
|
и бинарю права 700 root:root; юнит с User=mtproxy + NoNewPrivileges +
|
||||||
|
ProtectSystem=strict не может прочитать бинарь.
|
||||||
|
|
||||||
|
```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 # active (running), readyz → 200
|
||||||
|
```
|
||||||
|
|
||||||
|
## Флейк go test
|
||||||
|
|
||||||
|
Первый `go test ./...` (холодный кэш) упал:
|
||||||
|
`internal/config: TestLoadAcceptsSystemdCredentialReadPermissions:
|
||||||
|
group/other-readable profiles file outside a credential directory was accepted`.
|
||||||
|
Повторный (тёплый кэш) — PASS. Это гонка холодного параллельного прогона.
|
||||||
|
Перезапустить install.sh — идемпотентен.
|
||||||
|
|
||||||
|
## Мульти-секреты
|
||||||
|
|
||||||
|
profiles.json (пример на проде):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"profiles":[{"name":"default","secret":"<hex32>","backend":"127.0.0.1:2398"}]}
|
||||||
|
```
|
||||||
|
|
||||||
|
Добавить второй профиль → массив из двух объектов, `systemctl restart
|
||||||
|
tproxy-server`. Лимит max_profiles 32 (config.json). Права profiles.json — 600
|
||||||
|
root; LoadCredential читается при старте.
|
||||||
|
|
||||||
|
Формат secret: 16 байт (32 hex) обычный, или 17 байт с префиксом `dd`
|
||||||
|
(fake-TLS/DD). `openssl rand -hex 16` → обычный 32-hex, для Telegram Desktop
|
||||||
|
WEB Proxy это правильный формат.
|
||||||
|
|
||||||
|
## Проверка после установки (полная)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl status tproxy-server mtproxy tproxy-firewall caddy
|
||||||
|
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 cert
|
||||||
|
ss -tlnp | grep -E ':80 |:443|:2398|:8080|:8081'
|
||||||
|
nft list ruleset | grep -E '2398|8888'
|
||||||
|
```
|
||||||
|
|
||||||
|
Снаружи: 443 OPEN, 8080 refused (бэкенд скрыт), 2398 timeout (nft drop — не
|
||||||
|
светится). Сайт отдаётся на /, HTTP → 308 → HTTPS.
|
||||||
|
|
||||||
|
## Загрузка дерева без rsync
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tar czf - tproxy-server/ | ssh root@HOST 'mkdir -p /tmp/tproxy-server && tar xzf - -C /tmp'
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user