v1.14.0

sleep3r/mtproto.zigv1.14.0Aug 27, 2026by sleep3r

Upgrading?

AI Summary

Introduces WEB-only mode and bring-your-own certificate support, while fixing critical bugs where uninstall deleted tunnel configs and mtbuddy update broke existing hosts.

Key Highlights

  • New WEB-only mode restricts proxy to MTProto relay only.
  • Support for custom certificates via --cert and --key flags.
  • Fixed uninstall to only delete mtbuddy-created configs.
  • Fixed mtbuddy update compatibility with --mode behind hosts.

New Features

  • WEB-only mode
  • Custom certificate support
  • Safe uninstallation
  • Fix for --mode behind update

Full Release Notes

<details open>
<summary>🇷🇺 Что нового (RU)</summary>

## Коротко

`v1.14.0` закрывает два issue от операторов: **режим «только WEB»** ([#403](https://github.com/sleep3r/mtproto.zig/issues/403)) и **`uninstall`, который сносил чужие конфиги туннелей** ([#402](https://github.com/sleep3r/mtproto.zig/issues/402)).

> ⚠️ **Если на сервере есть свои конфиги AmneziaWG/WireGuard — обновитесь прежде, чем соберётесь делать `uninstall`.** Раньше он звал `rm -rf /etc/amnezia` и гасил все интерфейсы `awg*` — включая те, которые mtbuddy не создавал.

## Только WEB

Если IP блокируют ровно в тот момент, когда к нему напрямую подключается клиент Telegram, — уберите прямую дверь:

```bash
sudo mtbuddy setup web --domain relay.example.com --only
sudo mtbuddy links          # теперь только tg://webproxy
```

С `[web].only` прокси отвечает по MTProto релею и никому больше. Все остальные — включая настоящего клиента с валидной `ee`-ссылкой — уходят в masking-бэкенд ровно тем же путём, что и неверный секрет, так что пробер не отличит прокси от сайта, которым он прикрывается.

Цена честная: все выданные `ee`/`dd`-ссылки перестают работать, WEB-ссылку открывает только Desktop 7.1+, а `[web].max_sessions` становится потолком по пользователям. Выключить — `--no-only`.

## Свой сертификат

```bash
sudo mtbuddy setup web --domain relay.example.com \
  --cert /etc/ssl/relay/fullchain.pem --key /etc/ssl/relay/privkey.pem
```

`--skip-cert` был ловушкой: выпуск пропускал, но всё равно рисовал vhost с намертво зашитым `/etc/letsencrypt/live/<domain>/`. Теперь можно принести свой — acme.sh, wildcard, Cloudflare Origin. Самоподписанный по-прежнему не годится: WebView клиента проверяет цепочку.

## Что починено

- **`uninstall` удалял конфиги туннелей, которых mtbuddy не создавал** — вместе с приватными ключами и поднятыми интерфейсами. Теперь в свои конфиги пишется шапка `# Generated by mtbuddy`, удаляются только они, остальное остаётся на месте и перечисляется путями в конце. `--iface awgN <тот же путь>` — это принятие чужого конфига, и mtbuddy так и говорит.
- **`mtbuddy update` ломал хосты с `--mode behind`** — переустанавливал их как `mask`, падал на проверке masking и выходил до перезаписи юнита, оставляя релей на предыдущем бинарнике.
- **`setup egress`, умерший на полпути, оставлял приватный ключ провайдера** в `/etc/amnezia/.mtbuddy-stage-*.conf`.
- **`setup tunnel` без `--iface` целился в `awg0` вслепую**, если `config.toml` не читался, — и мог перезаписать чужой awg0.
- **installer-E2E проверял релиз, а не PR**: после шага update в контейнере оказывался released-бинарник mtbuddy, поэтому изменения в `setup tunnel` и `uninstall` не тестировались вообще.

## Проверено

`zig build test` — 372, `zig build e2e` — 19/19 (три сценария новые), installer-E2E — все пять ног. Плюс прогоны в контейнерах: uninstall удаляет только свои конфиги и перечисляет остальные, принятие чужого конфига оставляет его нетронутым.

Не проверено на живом сервере: WEB-only (нужен реальный домен для ACME).

## Changelog

- feat(web): WEB-only mode + bring-your-own cert; stop uninstall deleting tunnel configs mtbuddy never created ([#404](https://github.com/sleep3r/mtproto.zig/pull/404)) — closes [#402](https://github.com/sleep3r/mtproto.zig/issues/402), [#403](https://github.com/sleep3r/mtproto.zig/issues/403)

</details>

---

<details>
<summary>🇬🇧 Release notes (EN)</summary>

## TL;DR

`v1.14.0` closes two operator-reported issues: a **WEB-only mode** ([#403](https://github.com/sleep3r/mtproto.zig/issues/403)) and an **`uninstall` that deleted tunnel configs it never created** ([#402](https://github.com/sleep3r/mtproto.zig/issues/402)).

> ⚠️ **If the server has AmneziaWG/WireGuard configs of your own, update before you ever run `uninstall`.** It used to `rm -rf /etc/amnezia` and bring down every `awg*` interface — including the ones mtbuddy did not create.

## WEB-only

If the IP gets blocked the moment a Telegram client connects to it directly, stop offering that door:

```bash
sudo mtbuddy setup web --domain relay.example.com --only
sudo mtbuddy links          # tg://webproxy links, and nothing else
```

With `[web].only` the proxy answers MTProto for the relay and nobody else. Everyone else — including a real client holding a valid `ee` link — is handed to the masking backend on exactly the code path a wrong secret takes, so a probe cannot tell the proxy from the website it fronts.

The price is honest: every `ee`/`dd` link already handed out stops working, a WEB link opens in Desktop 7.1+ only, and `[web].max_sessions` becomes your user ceiling. Turn it off with `--no-only`.

## Bring your own certificate

```bash
sudo mtbuddy setup web --domain relay.example.com \
  --cert /etc/ssl/relay/fullchain.pem --key /etc/ssl/relay/privkey.pem
```

`--skip-cert` was a trap: it skipped issuance and still rendered a vhost hard-coded to `/etc/letsencrypt/live/<domain>/`. You can now point at your own — acme.sh, a wildcard, a Cloudflare Origin cert. Self-signed still does not work: the client's WebView validates the chain.

## Fixed

- **`uninstall` deleted tunnel configs mtbuddy never created** — private keys and running interfaces with them. Configs mtbuddy writes now carry a `# Generated by mtbuddy` banner, only those are removed, and everything else is left in place and named by path at the end of the run. `--iface awgN <that same path>` is an adoption, and mtbuddy says so.
- **`mtbuddy update` broke `--mode behind` hosts** — it re-ran them as `mask`, failed the masking precondition and returned before rewriting the unit, leaving the relay on the pre-upgrade binary.
- **A `setup egress` that died half-way left the provider's private key** in `/etc/amnezia/.mtbuddy-stage-*.conf`.
- **`setup tunnel` with no `--iface` blind-targeted `awg0`** when `config.toml` was unreadable — and could overwrite somebody else's awg0.
- **installer-E2E was testing the release, not the PR**: after the update step the container held the released mtbuddy, so changes to `setup tunnel` and `uninstall` were never exercised at all.

## Verified

`zig build test` — 372, `zig build e2e` — 19/19 (three new scenarios), installer E2E — all five legs. Plus container runs: uninstall removes only its own configs and lists the rest; adopting a foreign config leaves it untouched.

Not covered on a live server: WEB-only (needs a real domain for ACME).

## Changelog

- feat(web): WEB-only mode + bring-your-own cert; stop uninstall deleting tunnel configs mtbuddy never created ([#404](https://github.com/sleep3r/mtproto.zig/pull/404)) — closes [#402](https://github.com/sleep3r/mtproto.zig/issues/402), [#403](https://github.com/sleep3r/mtproto.zig/issues/403)

</details>

Related Repositories