Back to Home

MTProto proxy: personal secrets and policies

The article describes the implementation of personal MTProto proxies on Erlang with unique SNI domains. It covers the policy system for access control, connection limits, and user analytics. Examples of configuration and code are provided.

Personal MTProto Proxies: Erlang and Access Policy
Advertisement 728x90

Personal MTProto Proxies on Erlang: Policy System and Unique Secrets

MTProto proxies provide access to Telegram under censorship. The traditional model uses a single secret key for all users, leading to issues: lack of access control, inability to analyze user activity, and limited monetization. The solution is personal secrets with a unique SNI domain for each client, implemented in Erlang mtproto_proxy via a policy system.

This implementation scales through O(1) connection validation and runtime-configurable rules. It supports connection limits, access revocation, and activity tracking without server restart.

Advantages of Erlang for High-Load Proxies

Erlang/OTP is ideal for MTProto proxies due to its architecture designed for millions of long-lived connections:

Google AdInline article slot
  • Process isolation: Each connection is a separate lightweight process (~2 KB). A crash in one does not affect others.
  • Auto-scaling: BEAM distributes processes across all CPU cores without manual management.
  • Preemptive multitasking: No single client can monopolize a core.
  • Bit syntax for parsing: Safe parsing of TLS ClientHello in one line:
parse_client_hello(
  <<?TLS_REC_HANDSHAKE, ?TLS_10_VERSION, TlsFrameLen:16,
    ?TLS_TAG_CLIENT_HELLO, HelloLen:24, ?TLS_12_VERSION,
    Random:32/binary,
    SessIdLen, SessId:SessIdLen/binary,
    CipherSuitesLen:16, CipherSuites:CipherSuitesLen/binary,
    CompMethodsLen, CompMethods:CompMethodsLen/binary,
    ExtensionsLen:16, Extensions:ExtensionsLen/binary>>
) when TlsFrameLen >= 512, HelloLen >= 508 -> ...
  • Live monitoring: Remote console for inspecting tables and states.
  • Hot updates: Changing code and configuration without breaking connections.

Total code volume is 3500 lines, less than most alternatives.

SNI and Fake-TLS Secret Format

Server Name Indication (SNI) allows a client to specify a domain in ClientHello before completing the TLS handshake. Fake-TLS mimics TLS 1.3 ClientHello with a legitimate SNI, hiding MTProto inside encrypted fields.

Personal secret format:

Google AdInline article slot
0xEE | <16 random bytes> | <SNI domain in UTF-8>

Hex string for t.me/proxy:

ee<32 hex token><hex-encoded SNI>

Validation: HMAC ClientHello with a base secret (one per port). Uniqueness is based on the SNI domain from the extension.

Policy System: Access Rules

Policies are an ordered list of rules for each connection. The first unmet rule rejects the connection.

Google AdInline article slot

Rule Types

| Rule | Description |

|------|-------------|

| {in_table, Key, Table} | Key is in Table |

| {not_in_table, Key, Table} | Key is not in Table |

| {max_connections, [Key,...], N} | Connections by keys ≤ N |

Keys from Connection

  • tls_domain — SNI from fake-TLS
  • port_name — port name
  • client_ipv4/client_ipv6 — client IP
  • {client_ipv4_subnet, Mask} — subnet

Tables are in-memory hash tables, saved on config reload, lost on restart.

Policy for Personal Proxies

Basic policy:

{policy, [
  {in_table, tls_domain, personal_domains},
  {max_connections, [tls_domain], 30}
]}
  • Whitelist: tls_domain in personal_domains.
  • Limit: ≤30 simultaneous connections per domain (prevents link sharing).

Additions:

{max_connections, [client_ipv4], 30},
{not_in_table, client_ipv4, ip4_blacklist}

Launching a Standard Personal Proxy

sys.config

{mtproto_proxy, [
  {ports, [
    #{name => mtp_handler,
      listen_ip => "0.0.0.0",
      port => 443,
      secret => <<"d0d6e111bada5511fcce9584deadbeef">>,
      tag => <<"dcbe8f1493fa4cd9ab300891c0b5b326">>}
  ]},
  {allowed_protocols, [mtp_fake_tls]},
  {policy, [
    {in_table, tls_domain, personal_domains},
    {max_connections, [tls_domain], 100}
  ]}
]}

Domain Registration

mtp_proxy eval '
  mtp_policy_table:add(personal_domains, tls_domain, "alice42.example.com").'

Domain activates instantly.

Key Points

  • Personal SNI domains enable access control and analytics without changing the base secret.
  • Policies are checked in O(1), scaling to thousands of users.
  • Erlang ensures connection isolation and zero downtime.
  • Policy tables are managed runtime via Erlang RPC.
  • A 30-connection limit per domain prevents abuse.

— Editorial Team

Advertisement 728x90

Read Next