commit 402147d08cccd87478a9354ee78f3e2dbbccf130 Author: estorozhenko Date: Sun Sep 6 13:51:10 2026 +0000 Initial commit: Hermes skill tproxy-web-proxy diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..19c572f --- /dev/null +++ b/SKILL.md @@ -0,0 +1,108 @@ +--- +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 \ No newline at end of file diff --git a/references/tproxy-monitoring.md b/references/tproxy-monitoring.md new file mode 100644 index 0000000..5d36a9a --- /dev/null +++ b/references/tproxy-monitoring.md @@ -0,0 +1,85 @@ +# tproxy-server monitoring reference + +Admin HTTP endpoints (bound to `127.0.0.1:8081` = `admin_listen`, loopback only): + +| Endpoint | Returns | +|---|---| +| `/healthz` | always `200 ok` while the process runs; does NOT touch backends | +| `/readyz` | `200 ready` if TCP dial succeeds to EVERY profile backend; `503 backend unavailable` if any backend dial fails (timeout = `timeouts.backend_dial`, default 5s) | +| `/metrics` | Prometheus text format (`Content-Type: text/plain; version=0.0.4`), 13 counters | +| `/debug/pprof/*` | only when `config.enable_pprof: true` | + +## Metrics (from serveMetrics, internal/server/server.go) + +``` +tproxy_sessions_live # currently active sessions +tproxy_streams_live # currently active streams +tproxy_backend_dials_in_flight # in-flight dials to MTProxy (127.0.0.1:2398) +tproxy_pending_bytes # queued payload waiting to be relayed +tproxy_pending_items # queued items +tproxy_sessions_created_total # cumulative +tproxy_sessions_closed_total # cumulative +tproxy_streams_opened_total # cumulative +tproxy_streams_rejected_total # cumulative +tproxy_backend_dial_failures_total # cumulative — growth = MTProxy down/unreachable +tproxy_bytes_up_total # cumulative, client→proxy→backend +tproxy_bytes_down_total # cumulative, backend→client +tproxy_limit_hits_total # cumulative, rate-limit / capacity hits +``` + +Note: live values come from `manager.Capacity()` (current), `_total` counters +from `manager.Metrics()` (cumulative). No labels/help strings emitted — plain +`name value` lines. + +## Prometheus scrape config (prometheus runs network_mode: host) + +```yaml +- job_name: 'tproxy' + static_configs: + - targets: ['77.67.89.154:8081'] # vps03 public IP; port must be opened + labels: + host: vps03 + service: tproxy +``` + +## Exposing 8081 to the monitor (vps03, nft) + +Endpoint listens on loopback only — open for ONE source IP, e.g. bigbox: + +```bash +nft add rule inet filter input ip saddr tcp dport 8081 accept +systemctl restart tproxy-server # or nft reload +``` + +Never publish to 0.0.0.0; the endpoint has no auth. + +## Alert ideas + +- `tproxy_backend_dial_failures_total` increases → MTProxy unreachable +- `/readyz` non-200 → chain broken (but remember: ONE dead profile backend + fails readyz for everyone) +- `tproxy_limit_hits_total` increases → abuse / capacity exceeded +- `up{job="tproxy"} == 0` → exporter itself down + +## Monitoring task location + +`/opt/monitoring/PLAN.md` — «Этап 6. Метрики tproxy-server (vps03)» (written +2026-08-31), git repo `gitverse.ru:kpa39l/monitoring.git`, gitea mirror. + +## Verified live sample (vps03, 2026-08-31, idle-ish) + +``` +tproxy_sessions_live 1 +tproxy_streams_live 5 +tproxy_backend_dials_in_flight 0 +tproxy_pending_bytes 0 +tproxy_pending_items 0 +tproxy_sessions_created_total 1 +tproxy_sessions_closed_total 0 +tproxy_streams_opened_total 15 +tproxy_streams_rejected_total 0 +tproxy_backend_dial_failures_total 0 +tproxy_bytes_up_total 166853 +tproxy_bytes_down_total 5076719 +tproxy_limit_hits_total 0 +``` \ No newline at end of file