// DevOps

Telemt: installing MTProxy for Telegram in Docker on port 443 with Fake TLS

Published on 2026-05-29

Link to check how the installed TeleMT works

Telemt is an MTProxy server for Telegram written in Rust. Unlike the classic official image, it supports Fake TLS: traffic from outside looks like regular HTTPS to a real site, without a local SSL certificate. If someone connects to the port without the correct secret — DPI, a scanner, just a browser — the connection is transparently forwarded to the real github.com (or any other domain you specify). The inspecting party receives a live TLS handshake and understands nothing.

Below is a step-by-step installation in Docker Compose on port 443.


About SSL certificates — the main point

A local certificate is not needed. You don’t need Certbot, Let’s Encrypt, or ACME. You simply specify a real HTTPS domain in the config — Telemt uses it as a mask. This is a fundamental difference from Nginx or any classic proxy.


Step 1. Prepare the server

You need:

  • A Linux server with a public IP;
  • Docker Engine + Docker Compose plugin;
  • Free port 443.

First, check whether the port is occupied:

ss -ltnp 'sport = :443'

If Nginx or Caddy is already running there — either free the port, or run Telemt on another port and perform L4 forwarding.

Create the working directory:

install -d -m 0750 /opt/telemt
cd /opt/telemt

Step 2. Generate the secret

The secret is 16 bytes, i.e. 32 hex characters:

openssl rand -hex 16

Or without OpenSSL:

xxd -l 16 -p /dev/urandom

Example:

7a2f8b5c9d0e1f2a3b4c5d6e7f8a9b0c

Save this value — it goes into the [access.users] section. The config uses exactly this short hex. The full client link with the ee prefix and the domain code will appear in the logs after startup — you don’t need to assemble it manually.


Step 3. config.toml

nano /opt/telemt/config.toml

Minimal working config for Fake TLS:

[general]
use_middle_proxy = true
log_level = "normal"

[general.modes]
classic = false
secure = false
tls = true

[general.links]
show = "*"
# If you want a domain instead of IP in links:
# public_host = "proxy.example.com"
# public_port = 443

[server]
port = 443
max_connections = 10000

# Prometheus metrics — localhost only
metrics_port = 9090
metrics_whitelist = ["127.0.0.1/32", "::1/128"]

[server.api]
enabled = true
listen = "127.0.0.1:9091"
whitelist = ["127.0.0.1/32", "::1/128"]
minimal_runtime_enabled = false
minimal_runtime_cache_ttl_ms = 1000

[[server.listeners]]
ip = "0.0.0.0"

[censorship]
# Mask domain. Do not change after links are issued — links will break.
tls_domain = "github.com"
mask = true
tls_emulation = true
tls_front_dir = "tlsfront"

[access.users]
tg_user1 = "7a2f8b5c9d0e1f2a3b4c5d6e7f8a9b0c"

Replace github.com with any working HTTPS site, tg_user1 with a convenient name, and the hex string with your secret.

Important: tls_domain, mask, tls_emulation — all of these live in the [censorship] section, not in [general]. Put them in the wrong place — the config will not work.


Step 4. docker-compose.yml

nano /opt/telemt/docker-compose.yml
services:
  telemt:
    image: ghcr.io/telemt/telemt:latest
    container_name: telemt
    restart: unless-stopped

    ports:
      - "443:443"
      - "127.0.0.1:9090:9090"
      - "127.0.0.1:9091:9091"

    working_dir: /etc/telemt

    volumes:
      - ./config.toml:/etc/telemt/config.toml:ro

    tmpfs:
      - /etc/telemt:rw,mode=1777,size=4m

    environment:
      - RUST_LOG=info

    healthcheck:
      test: [ "CMD", "/app/telemt", "healthcheck", "/etc/telemt/config.toml", "--mode", "liveness" ]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 20s

    cap_drop:
      - ALL

    cap_add:
      - NET_BIND_SERVICE

    read_only: true

    security_opt:
      - no-new-privileges:true

    ulimits:
      nofile:
        soft: 65536
        hard: 262144

    logging:
      driver: json-file
      options:
        max-size: "50m"
        max-file: "5"

In production it’s better to pin the image version:

image: ghcr.io/telemt/telemt:3.4.12

NET_BIND_SERVICE is needed because the process inside the container doesn’t run as root but must listen on port 443 — a privileged port. Docker port binding by itself does not solve that.


Step 5. Start

cd /opt/telemt
docker compose up -d
docker compose ps
docker compose logs -f telemt

Links will appear in the logs:

tg://proxy?server=SERVER_IP&port=443&secret=ee...

This is the working link — ee + your 32-character secret + the domain hex code.


You can skip the logs and call the API:

curl -s http://127.0.0.1:9091/v1/users | jq -r '
  .data[]
  | "[\(.username)]",
    (.links.classic[]? | "classic: \(.)"),
    (.links.secure[]? | "secure: \(.)"),
    (.links.tls[]? | "tls: \(.)"),
    ""
'

If the command returns nothing — check server.api.listen, server.api.whitelist, and the Docker binding 127.0.0.1:9091:9091. Do not expose the API externally.


Step 7. Verify masking

Check that without the MTProxy secret the server behaves like regular HTTPS:

SERVER_IP="203.0.113.10"
TLS_DOMAIN="github.com"

curl -vkI --resolve "${TLS_DOMAIN}:443:${SERVER_IP}" "https://${TLS_DOMAIN}/"

TCP goes to your server, SNI indicates the tls_domain — the response should be a normal TLS from the real site.


Step 8. Multiple users

One secret per user:

openssl rand -hex 16
openssl rand -hex 16
openssl rand -hex 16
[access.users]
team1 = "00000000000000000000000000000001"
team2 = "00000000000000000000000000000002"
team3 = "00000000000000000000000000000003"

After editing the config, check via the API that the new users appeared. In theory reload works without restart, but in practice in a Docker environment I always run docker compose restart and check the logs.


If you don’t want one link to be used by a crowd:

[access.user_max_unique_ips]
team1 = 1

Limit by unique IPs. Devices behind the same NAT/router will appear as one IP.


Step 10. Prometheus metrics

curl http://127.0.0.1:9090/metrics

Do not expose metrics to the outside — 0.0.0.0/0 in metrics_whitelist opens them to everyone.


Troubleshooting

Port 443 is occupied

ss -ltnp 'sport = :443'

Find who occupied it and stop them or move Telemt to another port.

If you changed tls_domain — links broke, the domain is embedded in the ee secret. Reissue links via the API or logs.

Error Unknown TLS SNI

Clients with old links after changing the domain. You can mask it:

[censorship]
unknown_sni_action = "mask"

Or reject the handshake:

[censorship]
unknown_sni_action = "reject_handshake"

Telegram calls don’t work

MTProxy does not support calls — this is a limitation of Telegram itself, not Telemt. For calls you need SOCKS5 or a VPN.


Parameter reference

ParameterPurpose
use_middle_proxy = trueMiddle-End mode; when false — direct routing to DC.
[general.modes].tls = trueEnables Fake TLS / ee mode.
[censorship].tls_domainMask domain, included in client links.
[censorship].mask = trueFallback for unidentified connections.
[censorship].mask_hostSeparate upstream for masking. By default — tls_domain.
[censorship].tls_emulation = trueTLS emulation using cached data from real sites.
[server].metrics_portPrometheus metrics.
[server.api]Control API: users, links, runtime info.
[access.users]Users and their hex secrets.
[access.user_max_unique_ips]Limit of unique IPs per user.

Summary

Telemt is useful when the standard MTProxy is already blocked. Fake TLS makes the traffic indistinguishable from regular HTTPS — without dealing with certificates. Main points: do not change tls_domain after issuing links, keep the API and metrics bound to localhost only, and remember — MTProxy does not replace a VPN for calls and other Telegram features.

Link to check how the installed TeleMT works

// Reviews

Related reviews

I needed to get n8n, Redis, and the database working. I had hired another contractor before and everything kept breaking. I hired Mikhail, and the next day everything was working quickly, like clockwork!

There was a task to get n8n, redis and the database working. I had previously ordered from another contractor, it kept breaking all the time. Ordered from Mikhail, the next day everything started working fast, like …

christ_media

n8n installation on your VPS server. Configuration of n8n, Docker, AI, Telegram

2025-09-24 · ★ 5/5

Experienced buyer

Quick solution — I highly recommend Mikhail as a contractor! I tried to build a similar configuration myself and even followed AI advice, which ended up costing a lot of time and money (due to server downtime). So my advice: hire professionals — it's cheaper =) Thanks to Mikhail for his professionalism.

Quick fix for the problem, I recommend Mikhail as a contractor to everyone! I tried to assemble a similar configuration myself and following advice from neural networks, which resulted in a lot of wasted effort and …

ladohinpy

n8n installation on your VPS server. Configuration of n8n, Docker, AI, Telegram.

2025-08-25 · ★ 5/5

// Contact

Need help?

Get in touch with me and I'll help solve the problem

Send request
Write and get a quick reply