--- name: tproxy-web-proxy description: >- Operate tproxy-server (secrets, readyz, metrics). tags: - telegram - proxy - mtproto - web-proxy - systemd - prometheus category: devops --- # tproxy-web-proxy — Telegram WEB Proxy (telegramdesktop/tproxy-server) ## When to Use - Add / revoke client secrets (profiles) on a deployed tproxy-server («добавь ещё один секрет», «убери доступ другу») - Check proxy health (/readyz, /healthz) or answer what an endpoint returns - Wire /metrics into the Prometheus stack (/opt/monitoring) - Troubleshoot the service (Caddy → tproxy-server → MTProxy chain) - Deploy tproxy-server on a fresh VPS ## Architecture (deployed on vps03, 2026-08) ``` Telegram Desktop (WEB Proxy) --HTTPS 443--> Caddy (vps03.nixg.ru) --> tproxy-server :8080 (loopback) --> MTProxy :2398 (loopback) ``` Key files (Debian): - `/etc/tproxy-server/config.json` — main config (`listen` 127.0.0.1:8080, `admin_listen` 127.0.0.1:8081, `limits.max_profiles` default 32) - `/etc/tproxy-server/profiles.json` — ARRAY of client profiles (secrets), perms `600 root:tproxy` - `/etc/systemd/system/tproxy-server.service` — `ExecStart=/usr/local/bin/tproxy-server -config ...`, `LoadCredential=profiles.json:/etc/tproxy-server/profiles.json` - `/etc/tproxy-server/firewall.nft` — nft rules ## Multiple secrets (profiles) profiles.json is an ARRAY → many secrets supported (limit `max_profiles: 32`). Each profile points to the same MTProxy backend unless overridden — one MTProxy, many access keys. ```json {"profiles":[ {"name":"default","secret":"<32-hex>","backend":"127.0.0.1:2398"}, {"name":"rahuba","secret":"<32-hex>","backend":"127.0.0.1:2398"} ]} ``` Secret format: 16 bytes = 32 hex (plain) OR 17 bytes with `dd` prefix (fake-TLS mode). `openssl rand -hex 16` → plain 32-hex. Add a profile: 1. Edit `/etc/tproxy-server/profiles.json` (python3 json.dump for safety) 2. `chmod 600` + `chown root:tproxy` — systemd LoadCredential rejects group/other-readable files, unit fails to start otherwise 3. `systemctl restart tproxy-server` 4. Verify: `journalctl -u tproxy-server | grep 'event=started'` shows `profiles=N` (N = profile count); `curl :8081/readyz` → 200 Revoke: remove the profile object + restart. ## Admin endpoints (`admin_listen`, loopback only) - `/healthz` — process alive, always 200 `ok`; does NOT check backend - `/readyz` — TCP `net.DialTimeout` to EVERY profile's backend (5s); all ok → 200 `ready`; any dead → 503 `backend unavailable`. NOTE: one profile with a dead backend makes readyz fail for ALL. - `/metrics` — Prometheus text format (13 counters; full list, scrape config and alert ideas in `references/tproxy-monitoring.md`) - `/debug/pprof/*` — only when `enable_pprof: true` ## Pitfalls 1. **Install: `go test ./...` fails under root** — `TestLoadAcceptsSystemdCredentialReadPermissions` («group/other-readable profiles file outside a credential directory was accepted»). Run the build/tests as a non-root user, or skip that single test. Do NOT change `loadProfiles` semantics in upstream code. 2. **profiles.json permissions** — must not be group/other readable/writable (use `600 root:tproxy`). This is exactly what the config unit test enforces. 3. **readyz is per-backend** — a dead backend in any profile → 503 for everyone. 4. **Admin endpoints are loopback-only** — to expose /metrics to a remote Prometheus, open the port in nft restricted to the monitor's source IP (e.g. bigbox public IP), never 0.0.0.0. 5. **Restart required after every profiles.json change** — profiles are loaded once at start via LoadCredential. 6. **Keep secrets out of shell history** — pass via file `$(cat ...)`, never inline; tproxy logs never print secrets. ## Monitoring Full metrics table, readyz semantics, prometheus.yml job and alert ideas: `references/tproxy-monitoring.md`. Monitoring task lives in `/opt/monitoring/PLAN.md` («Этап 6. Метрики tproxy-server (vps03)»). ## Related Skills - `mtproto-proxy` — classic MTProto proxy via seriyps docker image (DIFFERENT product; tproxy-server is the official browser-based WEB proxy) - `networking-proxy` — umbrella for the XRay/AmneziaWG/Shadowsocks stack