mtg-multi

command module
v1.13.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 6, 2026 License: MIT Imports: 11 Imported by: 0

README

mtg-multi

Fork of 9seconds/mtg with multi-secret support and per-user stats.

English | Русский


What's different

Multiple secrets. Upstream mtg allows only one secret per instance. mtg-multi lets you define named secrets in the config — one per user. Secrets may use different hostnames for per-user domain fronting.

[secrets]
alice = "ee367a189aee18fa31c190054efd4a8e9573746f726167652e676f6f676c65617069732e636f6d"
bob   = "ee0123456789abcdef0123456789abcd9573746f726167652e676f6f676c65617069732e636f6d"

Stats API. A lightweight HTTP endpoint that shows live per-user traffic.

api-bind-to = "127.0.0.1:9090"
GET /stats
{
  "started_at": "2026-03-29T10:30:00Z",
  "uptime_seconds": 3600,
  "total_connections": 15,
  "users": {
    "alice": {
      "connections": 8,
      "bytes_in": 1048576,
      "bytes_out": 2097152,
      "last_seen": "2026-03-29T11:25:30Z"
    }
  }
}

Hot secret reload. The same api-bind-to listener also serves a reload endpoint, so the [secrets] set can change without restarting the proxy:

POST /reload

On success it re-reads the same config file passed to mtg run and swaps the [secrets] set in atomically. Added secrets work immediately; connections whose secret was removed or re-keyed are closed; every other user stays connected and their stats counters carry over. Only [secrets] is hot-applied — changing the bind address, domain fronting, network, or throttle still needs a restart. Responses: 200 {"status":"ok"}, 500 if the config cannot be read (the current set stays active), 503 when the proxy was started without a config file (simple-run), and 405 for a non-POST request.

Sponsored channel (ad-tag). Upstream mtg v2 dropped the promoted-channel feature; mtg-multi brings it back. Register your proxy with @MTProxybot to obtain a 32-character hex ad_tag. When it is set, matching clients are routed through Telegram middle proxies (the RPC protocol) instead of directly to the DCs, and a sponsored channel appears at the top of their chat list.

ad-tag = "0123456789abcdef0123456789abcdef"
public-ipv4 = "1.2.3.4"   # this proxy's reachable address, required by the middle proxy

One global tag applies to every secret; you can override it per secret:

[secret-ad-tags]
bob = "fedcba9876543210fedcba9876543210"

Notes: the middle-proxy path adds one hop and needs a reachable public IP (set public-ipv4/public-ipv6 if you are behind NAT or multi-homed). If a middle proxy cannot be reached, that connection falls back to a direct DC connection (logged as a warning) so the client stays online — the sponsored channel just will not show that time. The middle-proxy secret and address list are fetched from Telegram lazily on first use and refreshed hourly, so a proxy without an ad-tag never touches those endpoints.

Secrets & ad-tag management API. The api-bind-to listener also lets you manage secrets and the ad-tag at runtime, without editing the file or restarting:

GET    /secrets            list secrets (name, secret, host, ad_tag, effective_ad_tag)
POST   /secrets            add/update one: {"name","secret","ad_tag"?}
PUT    /secrets            replace the whole set: {"secrets":{name:{secret,ad_tag?}},"ad_tag"?}
DELETE /secrets/{name}     remove one (404 unknown, 409 if it is the last one)
GET    /adtag              read the global ad-tag: {"ad_tag":"<hex>"|null}
PUT    /adtag              set the global ad-tag: {"ad_tag":"<32 hex chars>"}
DELETE /adtag              clear the global ad-tag

These go through the same atomic-swap machinery as /reload: a changed secret key closes that user's connections, an ad-tag-only change does not. Direct API mutations are in-memory only — a later POST /reload (or a restart) re-reads the config file and overrides them.

API authentication. By default the API is unauthenticated and protected only by binding to loopback. Since the API can now mutate secrets, you can require a bearer token on every endpoint:

api-token = "change-me"
curl -H "Authorization: Bearer change-me" http://127.0.0.1:9090/secrets

Missing or wrong tokens get 401. When api-token is unset, behavior is unchanged (no auth).

Connection throttling. Automatic per-user connection limits to protect the server from overload. A background goroutine recomputes caps every few seconds using a fair-share algorithm: small users keep their connections, remaining budget is split equally among heavy consumers. New connections from over-cap users are rejected; existing connections are not killed.

[throttle]
max-connections = 5000
check-interval = "5s"

Example: limit = 100, users A=1, B=1, C=90, D=110. A and B stay at 1. Remaining budget 98 is split: C and D are capped at 49 each.

Throttle state is exposed via the Stats API:

{
  "throttle": {
    "active": true,
    "limit": 5000,
    "caps": { "heavy-user": 2450 }
  }
}

Public IP override. Useful when auto-detection via ifconfig.co is unavailable.

public-ipv4 = "1.2.3.4"
public-ipv6 = "2001:db8::1"

Everything else — domain fronting, doppelganger, proxy chaining, blocklists, metrics — works exactly as in upstream. See the upstream README for details.

Quick start

Download a binary from Releases or build from source:

git clone https://github.com/mhsanaei/mtg-multi.git
cd mtg-multi
mise install && mise tasks run build

Generate secrets:

mtg-multi generate-secret --hex storage.googleapis.com

Minimal config:

bind-to = "0.0.0.0:443"
api-bind-to = "127.0.0.1:9090"

[throttle]
max-connections = 5000

# [secrets] must be the last section in the global scope —
# in TOML, all keys after a [section] become part of that table.
[secrets]
alice = "ee..."
bob   = "ee..."

Run:

mtg-multi run /etc/mtg/config.toml

See example.config.toml for all available options.


Чем отличается

Несколько секретов. В оригинальном mtg — один секрет на инстанс. mtg-multi позволяет задать именованные секреты в конфиге, по одному на пользователя. Секреты могут использовать разные hostname для per-user domain fronting.

[secrets]
alice = "ee367a189aee18fa31c190054efd4a8e9573746f726167652e676f6f676c65617069732e636f6d"
bob   = "ee0123456789abcdef0123456789abcd9573746f726167652e676f6f676c65617069732e636f6d"

Stats API. HTTP-эндпоинт с live-статистикой трафика по пользователям.

api-bind-to = "127.0.0.1:9090"
GET /stats
{
  "started_at": "2026-03-29T10:30:00Z",
  "uptime_seconds": 3600,
  "total_connections": 15,
  "users": {
    "alice": {
      "connections": 8,
      "bytes_in": 1048576,
      "bytes_out": 2097152,
      "last_seen": "2026-03-29T11:25:30Z"
    }
  }
}

Рекламный канал (ad-tag). mtg v2 убрал поддержку промо-каналов; mtg-multi возвращает её. Зарегистрируйте прокси в @MTProxybot и получите ad_tag (32 hex-символа). Когда он задан, подходящие клиенты идут через middle-прокси Telegram (протокол RPC), а не напрямую в DC, и у них вверху списка чатов появляется спонсируемый канал.

ad-tag = "0123456789abcdef0123456789abcdef"
public-ipv4 = "1.2.3.4"   # доступный адрес этого прокси, нужен middle-прокси

[secret-ad-tags]
bob = "fedcba9876543210fedcba9876543210"   # переопределение тега для отдельного секрета

Если middle-прокси недоступен, соединение откатывается на прямое подключение к DC (с предупреждением в логе), чтобы клиент оставался онлайн. Секрет и список middle-прокси загружаются с Telegram лениво при первом использовании и обновляются раз в час.

API управления секретами и ad-tag. Тот же слушатель api-bind-to позволяет менять секреты и ad-tag на лету, без правки файла и рестарта:

POST   /reload             перечитать [secrets], ad-tag и [secret-ad-tags] из файла
GET    /secrets            список секретов
POST   /secrets            добавить/обновить один: {"name","secret","ad_tag"?}
PUT    /secrets            заменить весь набор
DELETE /secrets/{name}     удалить один
GET/PUT/DELETE /adtag      прочитать/задать/очистить глобальный ad-tag

Изменения через API применяются только в памяти — последующий POST /reload (или рестарт) перечитывает файл и перезаписывает их.

Аутентификация API. По умолчанию API без аутентификации и защищён только привязкой к loopback. Так как API теперь может менять секреты, можно включить bearer-токен на всех эндпоинтах:

api-token = "change-me"

Запросы без токена или с неверным токеном получают 401. Если api-token не задан — поведение прежнее (без аутентификации).

Троттлинг подключений. Автоматические per-user лимиты для защиты сервера от перегрузки. Фоновая горутина каждые несколько секунд пересчитывает капы по алгоритму fair-share: маленькие пользователи сохраняют свои подключения, оставшийся бюджет делится поровну между крупными потребителями. Новые подключения сверх капа отклоняются; существующие не разрываются.

[throttle]
max-connections = 5000
check-interval = "5s"

Пример: лимит = 100, пользователи A=1, B=1, C=90, D=110. A и B остаются на 1. Оставшийся бюджет 98 делится: C и D получают кап 49.

Состояние троттлинга доступно через Stats API:

{
  "throttle": {
    "active": true,
    "limit": 5000,
    "caps": { "heavy-user": 2450 }
  }
}

Ручное указание публичного IP. Для случаев, когда ifconfig.co недоступен с сервера.

public-ipv4 = "1.2.3.4"
public-ipv6 = "2001:db8::1"

Всё остальное — domain fronting, doppelganger, цепочки прокси, блоклисты, метрики — работает как в оригинале. Подробности в README upstream.

Быстрый старт

Скачайте бинарник из Releases или соберите из исходников:

git clone https://github.com/mhsanaei/mtg-multi.git
cd mtg-multi
mise install && mise tasks run build

Генерация секрета:

mtg-multi generate-secret --hex storage.googleapis.com

Минимальный конфиг:

bind-to = "0.0.0.0:443"
api-bind-to = "127.0.0.1:9090"

[throttle]
max-connections = 5000

# [secrets] должен быть последней секцией в глобальном scope —
# в TOML все ключи после [section] становятся частью этой таблицы.
[secrets]
alice = "ee..."
bob   = "ee..."

Запуск:

mtg-multi run /etc/mtg/config.toml

Все доступные опции — в example.config.toml.

Documentation

Overview

mtg is just a command-line application that starts a proxy.

Application logic is how to read a config and configure mtglib.Proxy. So, probably you need to read the documentation for mtglib package first.

mtglib is a core of the application. The rest of the packages provide some default implementations for the interfaces, defined in mtglib.

Directories

Path Synopsis
Antireplay package has cache implementations that are effective against replay attacks.
Antireplay package has cache implementations that are effective against replay attacks.
benchmarks
cmd/echo command
Echo server — runs on Amsterdam, simulates Telegram DC.
Echo server — runs on Amsterdam, simulates Telegram DC.
cmd/realnet command
cmd/relay command
Relay server — the process we measure.
Relay server — the process we measure.
This is a minimal package that contains _essentials_ of mtglib and its complimentary packages.
This is a minimal package that contains _essentials_ of mtglib and its complimentary packages.
Events has a default implementations of EventStream for mtglib.
Events has a default implementations of EventStream for mtglib.
internal
cli
Package ipblocklist contains default implementation of the mtglib.IPBlocklist for mtg.
Package ipblocklist contains default implementation of the mtglib.IPBlocklist for mtg.
files
files defines a set of abstraction for 'files': an openable entities that could be read after.
files defines a set of abstraction for 'files': an openable entities that could be read after.
Package logger has implementation of loggers for mtglib.Logger interface.
Package logger has implementation of loggers for mtglib.Logger interface.
mtglib defines a package with MTPROTO proxy.
mtglib defines a package with MTPROTO proxy.
dcprobe
Package dcprobe verifies that a TCP endpoint is a real Telegram DC by performing the unauthenticated first step of the MTProto handshake (req_pq_multi -> resPQ) on top of mtg's existing obfuscated2 transport.
Package dcprobe verifies that a TCP endpoint is a real Telegram DC by performing the unauthenticated first step of the MTProto handshake (req_pq_multi -> resPQ) on top of mtg's existing obfuscated2 transport.
internal/middleproxy
Package middleproxy implements the client side of Telegram's MTProto middle proxy (RPC) protocol.
Package middleproxy implements the client side of Telegram's MTProto middle proxy (RPC) protocol.
Network contains a default implementation of the network.
Network contains a default implementation of the network.
v2
Network contains a default implementation of the network.
Network contains a default implementation of the network.
Stats package has implementations of events.Observer for different monitoring systems.
Stats package has implementations of events.Observer for different monitoring systems.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL