Real MTProto handshake verification โ not just a port scan. If it says โ , the proxy actually works in Telegram.
mtproto-checker
Uses TDLib's testProxy โ the same path tdesktop uses. Not a TCP ping.
Direct links, remote URLs, local files, or any mix โ auto-detected per entry.
Re-check survivors across multiple rounds. Only stable proxies make the cut.
Built-in server with Basic Auth. Deploy anywhere, query from anything.
Auto de-duplicates by server:port:secret across all sources.
Extracts camouflage domains from ee-prefixed secrets automatically.
Install globally and run from anywhere
# Check proxies from remote URLs
TG_API_ID=12345 TG_API_HASH=abcdef check-proxies \
--url https://example.com/proxies.txt \
--iterations 2
# Check a single proxy link
check-proxies --proxy "tg://proxy?server=1.2.3.4&port=443&secret=ee..."
# Start HTTP server (no arguments)
CHECK_AUTH_USER=admin CHECK_AUTH_PASSWORD=secret check-proxies
| Flag | Default | Description |
|---|---|---|
--proxy <link> | โ | Check one proxy link directly |
--url <url> | โ | Source URL (repeatable) |
--sources <file> | โ | File of source URLs |
--dc <1-5> | 2 | Data center for testProxy |
--timeout <sec> | 10 | Per-proxy timeout |
--concurrency <n> | 30 | Parallel checks |
--iterations <n> | 1 | Re-check rounds |
--out <prefix> | result | Output file prefix |
Three functions, that's all you need
const { checkProxyLink, checkProxiesFromURIs, startServer } = require('mtproto-checker')
Check a single tg://proxy or https://t.me/proxy link via real MTProto handshake.
const results = await checkProxyLink(
'tg://proxy?server=1.2.3.4&port=443&secret=ee...',
{ apiId: 12345, apiHash: 'abcdef' }
)
Check proxies from remote URLs, local files, direct links, or any mix. Auto-detects and de-duplicates.
const results = await checkProxiesFromURIs([
'tg://proxy?server=1.2.3.4&port=443&secret=ee...',
'https://example.com/list.txt',
'./local-proxies.txt'
], { apiId: 12345, apiHash: 'abcdef', iterations: 2, concurrency: 20 })
Start the HTTP API server programmatically. All fields optional โ falls back to env vars.
const server = await startServer({
apiId: 12345,
apiHash: 'abcdef',
user: 'admin',
password: 'secret',
port: 8080
})
| Key | Type | Default | Description |
|---|---|---|---|
apiId | number | โ | Telegram API ID |
apiHash | string | โ | Telegram API Hash |
dc | number | 2 | Data center (1โ5) |
timeout | number | 10 | Timeout in seconds |
concurrency | number | 30 | Parallel checks |
iterations | number | 1 | Check rounds |
onProgress | function | โ | (proxy, res, i, total) => void |
POST /check โ accepts any mix of proxy links and list URLs
# Single proxy link
curl -u admin:secret https://your-server/check \
-H "Content-Type: application/json" \
-d '{"url": "tg://proxy?server=1.2.3.4&port=443&secret=ee..."}'
# Multiple sources
curl -u admin:secret https://your-server/check \
-H "Content-Type: application/json" \
-d '{"urls": ["https://example.com/list.txt", "tg://proxy?..."], "iterations": 2}'
| Field | Type | Default | Description |
|---|---|---|---|
url / urls / uri / uris | string | string[] | โ | Proxy link(s), list URL(s), or mix |
iterations | int | 1 | Check rounds |
concurrency | int | 30 | Parallel checks |
{
"uris": ["https://example.com/proxies.txt"],
"iterations": 2,
"concurrency": 20,
"count": 150,
"working": 42,
"results": [
{
"proxy": { "server": "1.2.3.4", "port": 443, "sni": "example.com" },
"ok": true,
"ms": 312,
"error": null
}
]
}
Real-world example โ proxy panel powered by mtproto-checker
SSL-terminated reverse proxy with automated CI/CD
/etc/mtproto-checker/ # source code (auto-pulled)
โโโ check.js
โโโ Dockerfile
โโโ package.json
โโโ ...
/opt/mtproto-checker/ # configs & certs (manual)
โโโ docker-compose.yml
โโโ default.conf
โโโ fullchain.pem
โโโ privkey.key
services:
app:
container_name: mtproto-checker
build: /etc/mtproto-checker
restart: unless-stopped
environment:
- TG_API_ID=your_api_id
- TG_API_HASH=your_api_hash
- CHECK_AUTH_USER=admin
- CHECK_AUTH_PASSWORD=your_password
- PORT=8080
expose:
- "8080"
nginx:
container_name: mtproto-checker-nginx
image: nginx:alpine
restart: unless-stopped
ports:
- "443:443"
- "80:80"
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf:ro
- ./privkey.key:/etc/nginx/ssl/privkey.key:ro
- ./fullchain.pem:/etc/nginx/ssl/fullchain.pem:ro
depends_on:
- app
server {
listen 443 ssl;
server_name _;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.key;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://app:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 600s;
}
}
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}
# Install acme.sh
sudo apt-get install cron socat
curl https://get.acme.sh | sh -s email=your@email.com && source ~/.bashrc
acme.sh --set-default-ca --server letsencrypt
# Issue certificate
acme.sh --issue --standalone -d 'your-domain.example.com' \
--key-file /opt/mtproto-checker/privkey.key \
--fullchain-file /opt/mtproto-checker/fullchain.pem
# Auto-renewal via cron โ verify:
crontab -l | grep acme
Generate a deploy key on the server, then add the private key as a GitHub Secret.
# On the server
ssh-keygen -t ed25519 -C "github-actions" -f ~/.ssh/github-actions -N ""
cat ~/.ssh/github-actions.pub >> ~/.ssh/authorized_keys
cat ~/.ssh/github-actions # copy this โ SSH_PRIVATE_KEY secret
| GitHub Secret | Value |
|---|---|
SERVER_HOST | Server IP or domain |
SERVER_USER | SSH username (e.g. root) |
SSH_PRIVATE_KEY | Content of ~/.ssh/github-actions |
Trigger manually: GitHub → Actions → Deploy → "Run workflow"
# Or deploy manually on the server:
cd /opt/mtproto-checker
docker compose build --no-cache
docker compose up -d