Skip to content

belaytzev/TDMeter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

22 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

TDMeter

TDMeter

MTProto Proxy Health Monitor
Two-stage health checks for Telegram MTProto proxies with a real-time web dashboard, Prometheus metrics, and monitoring integrations.

Quick Start Prometheus License: MIT


πŸ” What Is TDMeter?

TDMeter monitors your Telegram MTProto proxy servers by running two-stage health checks and reporting the results through a beautiful dark-themed web dashboard, a JSON API, per-proxy health endpoints, and Prometheus metrics.

No Telegram account or authentication is required. TDLib's proxy testing works in an unauthenticated state.

πŸš€ Key Features

  • πŸ”¬ Two-stage health checks β€” TCP connectivity test + TDLib MTProto protocol verification
  • πŸŸ’πŸŸ‘πŸ”΄ Three-state status model β€” Online, Degraded, and Offline for precise diagnostics
  • πŸ–₯️ Real-time web dashboard β€” Dark theme, auto-refresh, status filtering (Alpine.js + custom CSS)
  • πŸ“Š Prometheus metrics β€” Five gauges covering proxy status, latency, and check duration
  • 🩺 Per-proxy health endpoints β€” /health/{name} returns 200/503 for Uptime Kuma integration
  • πŸ”Œ JSON API β€” /api/status for custom integrations
  • πŸ”’ Optional Basic Auth β€” Protects web routes while keeping /metrics open for Prometheus
  • βš™οΈ YAML + env var config β€” File-based configuration with environment variable overrides
  • 🐳 Docker ready β€” Multi-stage build, single binary, ~30MB runtime image
  • πŸ“¦ Single binary β€” All templates and the logo are embedded via go:embed

βš™οΈ How It Works

TDMeter performs a two-stage check for every proxy on each interval:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 1     β”‚  OK  β”‚  Stage 2          β”‚  OK  β”‚  Status:         β”‚
β”‚  TCP Connect β”œβ”€β”€β”€β”€β”€β–Ίβ”‚  TDLib pingProxy  β”œβ”€β”€β”€β”€β”€β–Ίβ”‚  🟒 Online       β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚                       β”‚
       β”‚ FAIL                  β”‚ FAIL
       β–Ό                       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Status:         β”‚   β”‚  Status:         β”‚
β”‚  πŸ”΄ Offline      β”‚   β”‚  🟑 Degraded     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Status TCP TDLib Meaning
🟒 Online βœ… βœ… Proxy is fully functional
🟑 Degraded βœ… ❌ Server reachable but MTProto protocol fails
πŸ”΄ Offline ❌ β€” Server unreachable, TDLib check is skipped

πŸš€ Quick Start

🐳 Docker

# 1. Create your config file
cp config.example.yaml config.yaml
# Edit config.yaml with your Telegram API credentials and proxy list

# 2. Build and run
docker build -t tdmeter .
docker run -d \
  -v $(pwd)/config.yaml:/etc/tdmeter/config.yaml:ro \
  -p 2112:2112 \
  --name tdmeter \
  tdmeter

Open http://localhost:2112 for the dashboard, or check metrics at http://localhost:2112/metrics.

🐳 Docker Compose

Create a docker-compose.yml:

services:
  tdmeter:
    build: .
    volumes:
      - ./config.yaml:/etc/tdmeter/config.yaml:ro
    ports:
      - "2112:2112"
    restart: unless-stopped
docker compose up -d

πŸ’‘ Note: TDLib compilation requires 4GB+ RAM. The Docker build uses a three-stage approach:

  1. Build TDLib from source (Alpine + CMake)
  2. Build Go binary with CGO and static TDLib linking
  3. Minimal Alpine runtime image (~30MB)

πŸ”¨ Build from Source

πŸ“‹ Prerequisites

  • Go 1.24+
  • TDLib (built from source, pinned to commit 22d49d5 for go-tdlib v0.7.6 compatibility)
  • Telegram API credentials β€” api_id and api_hash from my.telegram.org

πŸ› οΈ Build

Install TDLib first. See the TDLib build instructions.

# Clone and build
git clone https://github.com/belaytzev/tdmeter.git
cd tdmeter

# Build with TDLib support (CGO required)
CGO_ENABLED=1 go build -tags=tdlib -o tdmeter .

# Copy and edit config
cp config.example.yaml config.yaml

# Run
./tdmeter --config config.yaml

πŸ§ͺ Running Tests

# Run unit tests (no TDLib required)
go test ./...

# TDLib integration tests require the tdlib build tag and a working TDLib installation
CGO_ENABLED=1 go test -tags=tdlib ./...

πŸ“ Configuration

TDMeter uses a YAML config file with optional environment variable overrides.

Copy config.example.yaml and edit it:

tdlib:
  api_id: 12345                          # From https://my.telegram.org
  api_hash: "your_api_hash_here"
  db_path: "/tmp/tdmeter-tdlib/"

proxies:
  - name: "proxy-eu-1"
    server: "proxy1.example.com"
    port: 443
    secret: "ee0123456789abcdef0123456789abcdef"

  - name: "proxy-us-1"
    server: "proxy2.example.com"
    port: 8443
    secret: "dd0123456789abcdef0123456789abcdef"

metrics:
  listen: ":2112"

web:
  auth:
    username: ""                          # Leave empty to disable auth
    password: ""

check_interval: 60s
tcp_timeout: 5s
tdlib_timeout: 10s
concurrency: 5

πŸ“‹ Config Reference

Field Default Description
tdlib.api_id (required) Telegram API ID
tdlib.api_hash (required) Telegram API Hash
tdlib.db_path /tmp/tdmeter-tdlib/ TDLib database directory
proxies (required, min 1) List of MTProto proxies to monitor
proxies[].name (required) Display name for the proxy
proxies[].server (required) Proxy server hostname or IP
proxies[].port (required) Proxy port (1-65535)
proxies[].secret (required) Hex-encoded MTProto secret
metrics.listen :2112 Address for HTTP server (dashboard + metrics)
web.auth.username (empty) Basic auth username (set both or neither)
web.auth.password (empty) Basic auth password (set both or neither)
check_interval 60s How often to run health checks
tcp_timeout 5s TCP connection timeout
tdlib_timeout 10s TDLib proxy test timeout
concurrency 5 Maximum concurrent proxy checks

πŸ”‘ MTProto Secret Format

Secrets are hex-encoded. The prefix byte determines the mode:

Prefix Mode Description
ee Fake-TLS Most common. Wraps MTProto in TLS to avoid detection
dd Padded intermediate Adds padding to obfuscate traffic patterns
(none) Simple intermediate Basic MTProto obfuscation

🌍 Environment Variable Overrides

Environment variables take precedence over YAML values:

Variable Overrides Example
TDMETER_API_ID tdlib.api_id TDMETER_API_ID=12345
TDMETER_API_HASH tdlib.api_hash TDMETER_API_HASH=abc123...
TDMETER_AUTH_USERNAME web.auth.username TDMETER_AUTH_USERNAME=admin
TDMETER_AUTH_PASSWORD web.auth.password TDMETER_AUTH_PASSWORD=secret

πŸ–₯️ Web Dashboard

TDMeter ships with a built-in dark-themed web dashboard at the root URL (/).

Dashboard features:

  • πŸ“Š Summary stats bar β€” total, online, degraded, offline counts at a glance
  • πŸ” Status filter buttons β€” quickly filter proxies by status
  • πŸ”„ Auto-refresh β€” polls the API on each check interval (toggleable)
  • ⚑ Latency display β€” shows RTT in milliseconds for online proxies
  • πŸ”— Health endpoint links β€” hover any proxy card to copy its health URL
  • πŸ“± Responsive design β€” works on desktop and mobile
  • 🎨 Custom logo support β€” replace web/logo.png and rebuild

🩺 Monitoring Integration

πŸ“‘ Uptime Kuma

TDMeter exposes per-proxy health endpoints designed for Uptime Kuma:

  1. In Uptime Kuma, create a new monitor of type HTTP(s)
  2. Set the URL to http://your-tdmeter:2112/health/{proxy-name}
  3. Set expected status code to 200
  4. The endpoint returns 200 when the proxy is online and 503 when degraded or offline

Example:

http://localhost:2112/health/proxy-eu-1  β†’  200 {"status":"online","latency_ms":142.5}
http://localhost:2112/health/proxy-us-1  β†’  503 {"status":"offline"}

πŸ’‘ Tip: If you enabled Basic Auth, configure the credentials in Uptime Kuma's authentication settings for the monitor.

πŸ“Š Prometheus + Grafana

Scrape the /metrics endpoint (always unauthenticated, even when Basic Auth is enabled):

# prometheus.yml
scrape_configs:
  - job_name: 'tdmeter'
    static_configs:
      - targets: ['tdmeter:2112']

πŸ”Œ API Endpoints

Endpoint Auth Method Description
/ πŸ”’ Optional GET Web dashboard (HTML)
/api/status πŸ”’ Optional GET All proxy statuses as JSON
/health/{name} πŸ”’ Optional GET Single proxy health (200/503)
/metrics πŸ”“ Open GET Prometheus metrics
/logo.png πŸ”“ Open GET Embedded logo image

πŸ”’ Optional = protected only when web.auth.username and web.auth.password are configured. πŸ”“ Open = always unauthenticated (so Prometheus can scrape without credentials).

πŸ“„ JSON API Response

GET /api/status

{
  "proxies": [
    {
      "name": "proxy-eu-1",
      "server": "proxy1.example.com",
      "port": "443",
      "status": "online",
      "latency_ms": 142.5
    },
    {
      "name": "proxy-us-1",
      "server": "proxy2.example.com",
      "port": "8443",
      "status": "offline",
      "latency_ms": -1
    }
  ],
  "last_check": "2025-01-15T12:00:05Z"
}

πŸ“Š Prometheus Metrics

Metric Type Labels Description
tdmeter_proxy_up Gauge name, server, port 1 if online, 0 otherwise
tdmeter_proxy_degraded Gauge name, server, port 1 if degraded, 0 otherwise
tdmeter_proxy_latency_ms Gauge name, server, port RTT in milliseconds, -1 if unreachable
tdmeter_check_duration_seconds Gauge β€” Wall-clock time of entire check round
tdmeter_proxies_total Gauge status Count of proxies by status (online/degraded/offline)

πŸ“ˆ Example Grafana Queries

# Proxy availability (1 = up, 0 = down)
tdmeter_proxy_up{name="proxy-eu-1"}

# Average latency across all online proxies
avg(tdmeter_proxy_latency_ms > 0)

# Count of offline proxies
tdmeter_proxies_total{status="offline"}

# Check round duration
tdmeter_check_duration_seconds

🐳 Docker Deployment

πŸ”§ Build Image

docker build -t tdmeter .

▢️ Run Container

docker run -d \
  -v $(pwd)/config.yaml:/etc/tdmeter/config.yaml:ro \
  -p 2112:2112 \
  --name tdmeter \
  --restart unless-stopped \
  tdmeter

πŸ” With Basic Auth via Environment Variables

docker run -d \
  -v $(pwd)/config.yaml:/etc/tdmeter/config.yaml:ro \
  -e TDMETER_AUTH_USERNAME=admin \
  -e TDMETER_AUTH_PASSWORD=supersecret \
  -p 2112:2112 \
  --name tdmeter \
  --restart unless-stopped \
  tdmeter

πŸ“‚ Project Structure

tdmeter/
β”œβ”€β”€ main.go                 # πŸš€ Entrypoint, HTTP server, signal handling
β”œβ”€β”€ config/
β”‚   └── config.go           # βš™οΈ YAML + env var config loading & validation
β”œβ”€β”€ checker/
β”‚   β”œβ”€β”€ checker.go          # πŸ” Status types, Checker interface, DetermineStatus
β”‚   β”œβ”€β”€ tcp.go              # 🌐 TCP connectivity checker
β”‚   └── tdlib.go            # πŸ“‘ TDLib MTProto proxy checker (build tag: tdlib)
β”œβ”€β”€ scheduler/
β”‚   └── scheduler.go        # ⏱️ Periodic check orchestrator with bounded concurrency
β”œβ”€β”€ metrics/
β”‚   └── metrics.go          # πŸ“Š Prometheus gauge registration & updates
β”œβ”€β”€ web/
β”‚   β”œβ”€β”€ handler.go          # πŸ–₯️ Dashboard, API, health, and logo handlers
β”‚   β”œβ”€β”€ auth.go             # πŸ”’ Basic auth middleware
β”‚   β”œβ”€β”€ store.go            # πŸ’Ύ Thread-safe status store
β”‚   β”œβ”€β”€ embed.go            # πŸ“¦ Embedded templates & logo (go:embed)
β”‚   β”œβ”€β”€ logo.png            # 🎨 Dashboard logo
β”‚   └── templates/
β”‚       └── index.html      # πŸ–₯️ Alpine.js dashboard template
β”œβ”€β”€ config.example.yaml     # πŸ“ Example configuration
β”œβ”€β”€ Dockerfile              # 🐳 Multi-stage build (TDLib + Go + Alpine)
└── README.md               # πŸ“– You are here

🀝 Contributing

Contributions are welcome! If you want to help:

  1. Fork the repository
  2. Create a branch for your changes
  3. Make and test your changes
  4. Create a Pull Request

πŸ“„ License

MIT

About

MTProto proxy checker base on TDLib

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors