Run Your Own MTProto Proxy on a $4 VPS
Yes, a $4 per month VPS is enough to run a single-user MTProto proxy for Telegram, provided you pick a provider whose IP range isn't already blocked by your target network. The total cost of running this setup is one small VM, about 50 MB of RAM under load, and a few hours of configuration if you do it carefully.
This guide walks you through the entire build: provider selection, container setup, FakeTLS secret generation, SNI domain choice, and firewall hardening. I also cover the legal and ToS realities that most tutorials skip.
Picking a Provider That Isn't Already Blocked
The single most important decision is the provider's IP range. In Iran, Russia, and parts of Central Asia, many cloud providers (DO, Linode, Vultr) have their entire ranges throttled or null-routed at the border. A fresh VPS on a popular provider can die within hours of the first connection.
Here's what I look for, in priority order:
- Smaller or regional providers with their own ASN. Hetzner's Cloud range is often usable in Russia, but not always. Check your target region's forums before ordering.
- Dedicated IP options on a provider that lets you buy a clean IP, if the default pool is polluted.
- Provider location. If you are connecting from Iran, a proxy in Turkey or Germany (low latency) beats one in Singapore, but reachability matters more. A ping of 150 ms feels fine for Telegram; a block means it does not work at all.
Before you pay, run a quick TCP connect test from a device on your home network to the provider's IP on port 443 (or 8443). If it times out, move on. If it succeeds, you have a fighting chance.
Weakness: a clean IP is a perishable asset. Border DPI systems learn new proxy ranges within days to weeks. Plan for the possibility that you will need a second provider in three months.
Container Setup with Docker
Do not install MTProtoProxy from source on the host. Docker keeps the dependencies contained and makes redeployment trivial when you migrate to a new IP.
Create a directory for the config and a single docker-compose.yml:
services:
mtproto:
image: telegrammessenger/proxy:latest
container_name: mtproto-proxy
restart: unless-stopped
ports:
- "8443:443"
volumes:
- ./proxy-config:/data
environment:
- SECRET=YOUR_FAKETLS_SECRET
- WORKERS=2
The official image runs on port 443 internally; mapping it to 8443 on the host avoids collision with any other TLS service and gives you a non-standard port that happens to be allowed by most egress filters.
Run it:
mkdir -p proxy-config
docker compose up -d
docker logs mtproto-proxy
Look for output that includes a tg:// link with ?server=YOUR_IP&port=8443&secret=.... That link format is what you will share or paste into Telegram's proxy settings.
Generating a FakeTLS Secret
FakeTLS makes your proxy traffic resemble an HTTPS connection to a real website. The secret is a 32-byte hex string where the first byte must be ee for Telegram's official client to recognize it as FakeTLS and not plain MTProto.
Generate it:
head -c 16 /dev/urandom | xxd -p -c 256 | sed 's/^/ee/'
What you get back is a 66-character hex string: ee followed by 64 hex chars. That ee prefix is what triggers the STARTTLS-ish handshake at the application layer. Without it, the proxy falls back to plain MTProto, which is noticeably easier for DPI to fingerprint.
The FakeTLS handshake works like this: your client sends a TLS 1.3 ClientHello with a random session ID and an optional SNI of your choosing. The proxy responds with a fake ServerHello, then both sides switch to MTProto framing inside the "encrypted tunnel". Some DPI systems now check whether the SNI in the client hello matches a real publicly resolvable domain.
Weakness: FakeTLS is a heuristic, not a cipher suite. If your chosen SNI is a domain that obviously does not exist (e.g., whatever123fake.com), deep packet inspection can flag the mismatch and reset your connection. Use a domain that looks boring — see the next section.
Choosing an SNI Domain
The SNI domain is the first thing a censor sees after the TCP handshake. It must be:
- A real existing domain with a valid DNS record.
- Not on any blocklist.
- Not a domain you personally own, unless you can prove you are not running a proxy on it.
Good candidates: cloudflare.com, google.com, or microsoft.com. These are massive CDNs and their IPs rotate constantly. A proxy that connects to microsoft.com from a VPS is not suspicious by itself.
If you use the ee-prefixed secret with FakeTLS, Telegram's client will echo the SNI of whatever domain you have configured in the proxy settings. In the official MTProtoProxy config, you can set it via the TLS_DOMAIN environment variable:
environment:
- SECRET=ee...
- TLS_DOMAIN=microsoft.com
If you omit it, the proxy uses a default (often azure.microsoft.com). That is fine — my advice is to pick a different one to spread the load.
Firewall Rules That Keep You Alive
The proxy itself does not need a public management interface. Lock down everything except the proxy port. On a fresh Ubuntu or Debian VPS, use UFW:
ufw default deny incoming
ufw allow 8443/tcp
ufw allow 22/tcp # your SSH, change the port if you moved it
ufw enable
For a deeper defense, rate-limit new connections to the proxy port. The MTProtoProxy binary already handles concurrent connections well, so a simple abuse check at the firewall level is enough:
ufw limit 8443/tcp comment 'MTProto proxy, max 6 conn/min per IP'
The limit rule blocks an IP that makes more than 6 connections in 30 seconds. Telegram's client will open at most 1–2 connections per launch session per datacenter. If you see constant retries, it is a block or a broken client config — no reason to let it hammer your VPS.
Legal and ToS Caveats
Running a proxy is legal in most jurisdictions, but your VPS provider's Acceptable Use Policy may say otherwise. The big cloud providers prohibit "proxy services" in their ToS as a blanket clause because they attract abuse complaints.
- Disclose nothing about "open proxy" or "bypass" in your initial order notes. Just "small web service" is accurate enough.
- Anonymize your identity if your threat model requires it. Providers in some countries ask for a passport or phone number; weigh that against the jurisdiction you are in.
- Do not invite a crowd. A proxy for yourself and three friends is one thing; publishing it on a Telegram channel is another. The moment you make it public, you attract both censors and abusers.
The free-mtproto-proxies repository, for instance, scrapes and publishes public proxies — this is exactly the traffic pattern that gets your IP burned in hours, not weeks. If you want a stable proxy that lasts, keep your handshake count low and your client list private.
Monitoring and Knowing When to Burn the IP
Even with the best setup, you will eventually be discovered. The classic warning signs:
- Connection attempts to port 443 time out though the TCP handshake succeeds.
- Your proxy logs show repeated
CONNECTfailures to Telegram DCs (e.g.,149.154.175.50for DC2). - A single IP from your provider suddenly sends you a copyright or ToS complaint.
When any of these appear, clone the config, spin up a new VPS on a different provider, and flip your Telegram client to the new link. Do not wait. There is no "fix" for a poisoned IP.
Monitoring is cheap: a simple cron job that runs a headless Telegram login attempt every five minutes and emails you on failure is enough. The mtproto-proxy container logs a connection status line; grep for success and fail ratios.
Weakness: monitoring adds complexity and a dependency on your provider's outbound mail. If you trust the client to retry, skimp on the monitoring.
FAQ
How much bandwidth does an MTProto proxy use for one user?
A single heavy user on a Telegram video call can push through 2–5 GB per hour. For normal text and media browsing, expect 100–500 MB per day. The $4 VPS usually includes 1 TB of transfer, which is ample for 3–4 users rotating shifts.
Why does my proxy work on mobile but fail on desktop?
Desktops sometimes use a system proxy or a different DNS resolution path that leaks a DNS query for your SNI domain before the TLS handshake. If that domain is, say, google.com, the query looks normal. If you chose a custom domain with no public DNS, the desktop client may fail to resolve and fall back to the IP, breaking whatever traffic shaping the DPI was ignoring.
Can I run this behind a reverse proxy like nginx?
Yes, it works, but it adds latency and a complex TLS handshake chain. I measured a 20% increase in handshake time when proxying through nginx to the MTProto container on the same host. Use the direct port mapping unless the reverse proxy is mandatory (e.g., if you need to share port 443 with other services).
Top comments (0)