tproxy-server: a Telegram WEB proxy that hides the relay behind an ordinary HTTPS site
Proof-of-concept WEB proxy server for Telegram
At a glance
- What is it?
- tproxy-server is the hosted half of a proof-of-concept Telegram WEB proxy type. It multiplexes MTProxy streams through a WebView carrier and connects each one to a stock MTProxy, and it is meant for operators who can run a dedicated hostname and a real public website.
- Who is it for?
- Adopt tproxy-server only if you control a dedicated lowercase hostname, can give Caddy ports 80 and 443 on a clean x86_64 host, and can supply a real public website rather than the placeholder the repository omits on purpose. Skip it if your server already terminates TLS for other sites, if you need a released artefact with a version number, or if you expect the relay to inspect or route Telegram traffic.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What tproxy-server solves, and for whom
A Telegram app can already speak MTProxy: normal framing, normal encryption, a host and a secret. The problem tproxy-server addresses is the shape of that connection on the wire. Instead of a long-lived TCP stream to an unusual port, the app sends every proxy connection through one WebView transport, and that transport carries a multiplexed session over a server-selected same-origin HTTPS or WebSocket carrier. The relay on the other end separates the logical streams again and connects each one to a stock official MTProxy.
The README states the design is not tied to one Telegram client or operating system. Any app that can host a WebView and connect its MTProxy sockets to a small local adapter can implement the client side. The proof-of-concept work named in the README includes a Telegram Desktop implementation, an experimental Android client described in ANDROID.md, and an iOS client plan in IOS.md. That is the audience: people building or operating this client half, plus operators willing to run the server half on their own hardware.
The configured hostname stays a regular HTTPS website. A capability derived from the hostname and the MTProxy secret selects a one-shot bridge page, and requests without authentic relay credentials get the public site. That is the whole point of the project: there is no separately hosted relay path for an unauthenticated prober to compare against the site.
The data flow: WebView carrier, OPEN/DATA/WINDOW/CLOSE frames, local MTProxy
The README gives the flow directly. Telegram app MTProto connections with the normal MTProxy transform reach a local WEB proxy adapter, which keeps one logical stream per app connection. Those streams go into one WebView transport and authenticated relay session, carried as multiplexed frames in the selected HTTPS or WebSocket carrier. On the server, tproxy-server turns each stream back into one local TCP connection to the official MTProxy.
The app configures only a hostname and an MTProxy secret. It derives the bridge capability locally and never exposes the raw secret to JavaScript. The WebView opens the bridge, exchanges a short-lived bootstrap token for a relay session, and runs the carrier mode selected by the matching server profile. OPEN, DATA, WINDOW, and CLOSE frames multiplex every app connection through that session. The relay treats DATA as opaque bytes: it cannot choose a Telegram destination and cannot decrypt the MTProxy stream.
One WebView transport means one logical carrier and relay session for the app, not one HTTP request or backend connection. The README lists the profile options: the original serialized HTTPS carrier, independent HTTPS request lanes per Telegram logical session, one multiplexed WebSocket, or an independent WebSocket per logical session. PROTOCOL.md is named as the normative wire contract, and PLAN.md as the place for architecture, limits, implementation rationale, and remaining proof-of-concept work. If you are writing a client, PROTOCOL.md is the document that matters, not this article.
Deployment layout and what the installer will overwrite
The reference layout puts Caddy on :80 and :443, tproxy-server on 127.0.0.1:8080, and the official MTProxy on 127.0.0.1:2398. Only Caddy listens on external interfaces. The relay, its admin endpoints, the official MTProxy client port, and MTProxy statistics stay local. Caddy proxies every path to the relay. In static mode the relay serves the whole site from memory using standard Go conditional and range handling. In application mode it delegates ordinary and unauthenticated requests to one private loopback web application, and a request that proves knowledge of a bridge or session token is intercepted before that application.
The requirements are explicit: a dedicated lowercase hostname you control, an x86_64 Linux server with a public IPv4 address, SSH, systemd, and either Ubuntu 22.04+ or Debian 12+, root or passwordless sudo, public inbound TCP 80 and 443, one random 16-byte secret, and an operator-owned static site or a loopback-bound web application.
The installer is the part to read carefully before running. The README says it is intended for a clean server on which Caddy may own ports 80/443, that it backs up an existing /etc/caddy/Caddyfile, and that it then replaces the active Caddy configuration. If the server already hosts other sites, the README points to the manual integration section instead. That is a real constraint, not a footnote: on a shared host you are choosing between the manual path and breaking the other sites' TLS routing.
Installing tproxy-server: hostname, secret, first run
Start at the DNS provider. Add an A record pointing the chosen hostname at the server's public IPv4 address, and add an AAAA record only when the server really has working public IPv6. The README also says not to put a CDN or HTTP proxy in front of this first deployment. Wait until the record resolves from outside your network, then confirm both record types:
dig +short A proxy.example.com
dig +short AAAA proxy.example.comGenerate the client-facing secret on your own computer. The README's command produces 32 lowercase hexadecimal characters, and that exact value is entered in every client that uses this server and passed to the installer:
openssl rand -hex 16One detail matters more than it looks. If the hostname is internationalised, publish it in its ACE form: the desktop client stores and derives the capability from the A-label, and the README warns that a hand-typed Unicode host containing ß, ς, ZWJ/ZWNJ, or characters newer than Unicode 3.2 can be mapped differently by the Qt 5.15 (Windows) and Qt 6 (macOS/Linux) desktop builds, deriving a different capability. ACE input round-trips unchanged on every platform.
Prepare the public site before the relay. The repository deliberately does not include a deployable public website, on the stated grounds that if many operators installed the same starter its body and assets would become an easy active-probing signature. The recommended choice is a real loopback website or stock static server configured with public_upstream. The in-process public_dir mode remains available for simple sites, and the only required file is index.html. A several-page site will normally also have about.html, privacy.html, 404.html, styles.css, a favicon, and images. Use exact links such as /about.html, or explicitly select static_routes: "legacy" for extensionless aliases. For a database-backed site, accounts, forms, server rendering, an existing CMS, site APIs, SSE, or WebSockets, run any HTTP application on a numeric loopback address such as 127.0.0.1:3000 and point public_upstream at it while the relay stays the only public gateway.
Restart the relay after changing files under public_dir. The README states the static site is read once at start-up, so editing a file in place changes nothing until the process comes back.
Where tproxy-server is the wrong tool
The project is a proof of concept, and the README says so in its first sentence. There are no retrieved releases, so there is no version tag to pin, no changelog to diff against, and no upgrade path documented in the README. If your organisation requires a released artefact with a semantic version and a support window, this is not that.
The installer's behaviour rules out shared servers. It backs up the existing Caddyfile and then replaces the active Caddy configuration, so any other site terminating TLS through that Caddy instance is affected. The README's answer is the manual integration section, which means the automated path is not the path you will use.
The relay also cannot do several things an operator might assume. It never receives a client-selected backend address, so it cannot route to different upstreams per client. It treats DATA as opaque bytes, so it cannot inspect, log, or filter Telegram destinations, and it cannot decrypt the MTProxy stream. If your goal is per-user policy, traffic accounting by destination, or content filtering, the architecture is pointed away from it.
The public site is a genuine operational burden rather than a checkbox. Because the repository ships no deployable website, you must supply one, and the README's reasoning is that a shared starter becomes a probing signature. An operator who cannot produce a plausible site is left with a bridge page that is easier to distinguish from ordinary traffic.
How this differs from putting Caddy in front of a stock MTProxy
The obvious alternative is an ordinary reverse proxy in front of a stock MTProxy, with clients connecting to the MTProxy directly. That is simpler to operate: no local adapter, no WebView, no bridge capability, no shared frame format. tproxy-server exists because the client side of that arrangement looks like what it is. Here the app's proxy connections never leave the WebView transport as separate sockets, the hostname serves a real site on every path, and only GET /?bridge=<valid capability> reveals the bridge.
The trade is complexity and coupling. You now depend on a client that implements the local adapter and the frame format, on PROTOCOL.md staying stable, and on a server profile matching the carrier mode the client selects. The README's list of carrier modes (serialized HTTPS, independent HTTPS request lanes, one multiplexed WebSocket, independent WebSocket per logical session) is also a list of behaviours you may have to test against whatever client build your users run.
Compared with a plain static host serving a decoy page, the difference is that tproxy-server is the gateway for both the site and the relay. There is no second listener to fingerprint, and unauthenticated requests on transport paths reach the loopback application unchanged apart from normal HTTP proxying. That property is the reason to accept the extra moving parts, and it is also the property to verify first if you deploy.
Maintenance, licensing and upgrade cost
The repository is not archived, and the last push was on 2026-09-10, so the codebase is current as of that date. There are no retrieved releases, which means upgrades happen by pulling the default branch. The README does not document rollback, and it does not describe a migration procedure for config changes. The only upgrade-adjacent instruction in the README is the restart requirement for public_dir, because the static site is read once at start-up.
The dependency surface is small. go.mod declares module github.com/telegramdesktop/tproxy-server, Go 1.20, and a single direct requirement, github.com/gorilla/websocket v1.5.3. A one-dependency Go server is cheap to build and cheap to re-read, which lowers the cost of tracking the branch manually.
The licence is not stated in the README or in go.mod. There is no LICENSE file among the top-level repository entries, and no licence identifier appears anywhere in the files listed. Treat that as an open question to resolve before you redistribute anything or run it commercially; this is a factual gap in the repository, not a legal opinion, and the answer has to come from the maintainers.
The other maintenance cost is the public site. You own its content, its links and its assets, and the README's warning about a shared starter applies to every change you make to it.
Editorial conclusion
Adopt tproxy-server only if you control a dedicated lowercase hostname, can give Caddy ports 80 and 443 on a clean x86_64 host, and can supply a real public website rather than the placeholder the repository omits on purpose. Skip it if your server already terminates TLS for other sites, if you need a released artefact with a version number, or if you expect the relay to inspect or route Telegram traffic. Before committing, verify three things: that your hostname resolves in its ACE form from outside your network, that your public site is not the same starter everyone else would deploy, and that you have read PROTOCOL.md and PLAN.md, because the README alone does not cover the wire contract or the remaining proof-of-concept work.
Frequently asked questions
Is using a proxy server illegal?
The README does not address legality. tproxy-server is described as a proof-of-concept WEB proxy type for Telegram, and the documentation covers deployment, protocol and site requirements only. Whether running or using a proxy is lawful in your jurisdiction is outside what the repository documents.
What are the top 10 proxy servers?
The README does not rank or compare proxy servers. It describes one project, tproxy-server, which is the hosted half of a proof-of-concept Telegram WEB proxy type and connects each logical stream to a stock official MTProxy on the same server.
What is a TCP proxy and how does it work?
tproxy-server is not described as a general TCP proxy. It connects each Telegram logical stream to one local TCP connection to a stock official MTProxy, while the client side carries those streams through a WebView transport using OPEN, DATA, WINDOW and CLOSE frames. The relay treats DATA as opaque bytes and cannot decrypt the MTProxy stream.
What exactly is a proxy server?
In this project the proxy server is the hosted half: tproxy-server runs on 127.0.0.1:8080 behind Caddy, separates the multiplexed logical streams again, and forwards each one to the official MTProxy on 127.0.0.1:2398. Only Caddy listens on external interfaces.
what is transparent proxy server
The README does not use the term transparent proxy. The closest documented behaviour is that Caddy proxies every path to tproxy-server, and a request that proves knowledge of a bridge or session token is intercepted before the loopback application, so only GET /?bridge=<valid capability> reveals the bridge.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/telegramdesktop-tproxy-server)