WEB: Common Profiles for multiple vhosts

This commit is contained in:
Alexey
2026-10-30 19:10:01 +03:00
parent 5035d549bd
commit e7e588ebe5
2 changed files with 347 additions and 12 deletions
+177 -6
View File
@@ -115,8 +115,177 @@ Die Behandlung überlasteter angenommener Sockets ist separat konfigurierbar. `d
`decoy_fasttrack_mode` steuert ausschließlich die Capability-Verarbeitung für `GET/HEAD` am konfigurierten Basis-Root. `off` ist der Default und behält den vollständigen bisherigen Scan ohne Fast-Track-Zähler bei. `shadow` erfasst, welche strukturell unmöglichen Requests den Scan umgehen könnten, führt ihn aber weiterhin vollständig aus. `enforce` umgeht Capability-Arbeit nur bei `HEAD` oder fehlender beziehungsweise nicht kanonischer `bridge`-Query. Jeder exakte kanonische Bridge-GET am Basis-Root scannt bei Treffer und Fehlschlag vollständig alle Profile des ausgewählten vhost. Die Einstellung erfordert einen Prozessneustart; Reload speichert den gewünschten Wert, meldet `web.decoy_fasttrack_mode` aber als zurückgestellt. Fast-Track schützt nicht vor gegnerischer CPU-Last, da ein Scanner stets kanonische Kandidaten senden kann; `enforce` kann außerdem eine öffentliche Timing-Klasse der Request-Form sichtbar machen, insbesondere bei einem statischen Decoy. Aktivieren Sie diesen Modus nicht ohne externe Timing-Messungen über den produktiven TLS-Terminator.
## Gemeinsame Profile für mehrere Hostnamen
Ersetzen Sie den Selektor `host` durch eine nicht leere Liste `hosts`, damit
mehrere Domains dieselben Profildefinitionen und denselben Decoy-Snapshot nutzen:
```toml
[[web.vhosts]]
hosts = ["proxy.example.com", "backup.example.com"]
base_path = "telegram/web"
public_addr = "203.0.113.10:443"
[web.vhosts.decoy]
mode = "http_upstream"
upstream = "http://127.0.0.1:18081"
[[web.vhosts.profiles]]
user = "web-user"
secret_mode = "dd"
max_sessions = 8
max_streams = 512
max_streams_per_session = 64
```
Dieses Fragment ergänzt den Zugangsbenutzer und WEB-Listener aus dem vorherigen
Beispiel. Geben Sie genau einen Selektor an: `host` oder `hosts`. Hostnamen werden
beim Laden normalisiert; danach identische Namen werden abgewiesen. Wildcard-Muster
und `*` erfordern die unten beschriebene ausdrückliche Aktivierung. Alle Mitglieder
teilen `base_path`, `public_addr`, Profile und Decoy. Bei abweichenden Einstellungen
sind getrennte Gruppen nötig. Der TLS-Terminator muss jeden aufgeführten Hostnamen
bedienen und den ursprünglichen kanonischen `Host` weiterreichen.
Jeder Hostname hat eigene Capabilities, Bootstrap-/Sitzungszuordnungen und
Profilquoten. Das Beispiel erlaubt bis zu acht Sitzungen dieses Profils je Domain,
weiterhin begrenzt durch Prozess-, IP- und Zugangsbenutzerlimits. Beim Start werden
Links für jeden ausgewählten Benutzer/jedes Profil und jeden konkreten Hostnamen
ausgegeben. Die Gruppierung leitet Clients nicht um und macht Zugangsdaten nicht
zwischen Aliasnamen übertragbar.
Bei exakten Namen zählt `max_vhosts` jeden Hostnamen und `max_profiles` jedes
Host-/Profilpaar. Acht Domains mit 100 Profilen benötigen beispielsweise mindestens
acht vhosts und 800 profiles. Statische Dateien und Bytes eines Gruppensnapshots
werden einmal gezählt; getrennte Gruppen behalten getrennte Snapshots. Konfigurierte
Sitzungsobergrenzen reservieren keine Sitzungen vorab. Gemeinsame unveränderliche
Richtlinien reduzieren Duplikate, Capability-Indizes wachsen aber weiterhin mit
der Anzahl der Host-/Profilpaare.
Installieren Sie zuerst die neue Binärdatei mit der bisherigen Konfiguration
einzelner `host`-Einträge. Fassen Sie danach gleich konfigurierte Einträge per Reload
zusammen. Gruppierung und Umordnung erhalten kompatible Bootstrap-Zugangsdaten,
Quotenidentitäten und Lerndaten der Profile. Das Entfernen eines Aliasnamens weist
neue Requests für diesen Namen ab, ohne neue Abbruchregeln für bestehende
Verbindungen einzuführen. Höhere Limits erfordern einen Neustart und müssen vor
dem Hinzufügen von Bindungen oberhalb der aktiven Grenzen wirksam sein. Vor einem
Downgrade auf eine Version ohne `hosts` müssen Gruppen wieder in einzelne
`host`-Einträge aufgeteilt und die Budgets statischer Snapshots geprüft werden.
## Automatische Wildcard-Hosts
Exakte `host`-/`hosts`-Einträge bleiben der Standard. Für beliebige Subdomains
setzen Sie `web.allow_wildcard_hosts = true` und starten Telemt neu. Die vorhandenen
Selektoren akzeptieren dann auch `*.example.com` und `*`, einschließlich gemischter
Listen aus exakten Namen und Mustern:
```toml
[web]
enabled = true
allow_wildcard_hosts = true
[web.limits]
# Additional wildcard reservations must fit the declared envelope.
memory_envelope_bytes = 1610612736
[web.limits.wildcard]
max_rules = 32
max_profiles_per_request = 256
cache_hosts = 256
cache_bytes = 8388608
cold_hmac_per_minute = 1000000
cold_hmac_burst = 65536
[[web.vhosts]]
hosts = ["proxy.example.com", "*.example.com"]
base_path = "relay"
public_addr = "203.0.113.10:443"
[web.vhosts.decoy]
mode = "http_upstream"
upstream = "http://127.0.0.1:8080"
[[web.vhosts.profiles]]
user = "web-user"
secret_mode = "dd"
```
Das Beispiel ergänzt den zuvor gezeigten Listener und Zugangsbenutzer. Ein Request
wählt genau eine Gruppe: zuerst den exakten Host, dann das längste passende Suffix,
dann `*`. Ein Suffix erfasst Nachfahren beliebiger Tiefe, auch `a.b.example.com`,
aber nicht den Stammnamen `example.com`. Fehlgeschlagene Authentifizierung fällt
nicht auf eine andere Regel zurück. Eingebettete Wildcards, reguläre Ausdrücke und
nach der Normalisierung doppelte Selektoren zwischen Gruppen sind unzulässig.
Die ausgewählte Gruppe behält ihre festen Werte für `public_addr`, Basispfad,
Profile und Decoy. Der Request-Host bestimmt keine Upstream-Adresse.
In diesem Modus wird HTTP Host ohne Beachtung der ASCII-Groß-/Kleinschreibung
normalisiert; entfernt wird nur ein optionales wörtliches `:443`. Doppelte
Host-Header, IP-Literale, ungültige DNS-/ACE-Labels, abschließende Punkte und andere
Ports werden abgewiesen. `X-Forwarded-Host` wird nicht ausgewertet. Capabilities
verwenden den tatsächlichen kanonischen Hostnamen und die bestehende
Client-Ableitung; Clientänderungen sind nicht nötig. Sitzungs-/Stream-/Profilquoten
bleiben an das konkrete Tupel `(host, user, secret_mode)` gebunden; Prozess-, IP-
und Zugangsbenutzerlimits gelten weiterhin. Startlinks enthalten nur konfigurierte
exakte Hostnamen.
Das Frontend **muss zulässige Host-Werte einschränken**; das unverschlüsselte WEB-
Backend muss privat erreichbar bleiben. TLS-Zertifikate müssen jeden tatsächlichen
Client-Hostnamen abdecken. Dies ist eine ausdrückliche Sicherheitsgrenze: Eine
Capability für einen unbekannten oder aus dem Cache verdrängten fremden Wildcard-
Host kann bei Übermittlung an einen anderen Host dessen Decoy erreichen, auch bei
einem exakten Host in einer gemischten Konfiguration. Capabilities des aktuellen
Hosts, der endlichen exakten Hostliste und des bekannten Positiv-Caches sowie
authentische Bootstrap-/Sitzungstokens des Prozesses bleiben in Request-URI und
Header-Metadaten lokal, einschließlich percent-encoded Formen. Öffentliche URLs,
Cookies und Header werden nicht allein wegen ihrer Ähnlichkeit mit Zugangsdaten
abgewiesen. Diagnosekopien maskieren dagegen vorsorglich ähnlich aussehende Texte,
auch abgeschnittene Präfixe; öffentliche Request-/Response-Bytes und ursprüngliche
User-Agent-Hashes bleiben unverändert. Daher kann die Diagnose auch gewöhnliche
lange Zeichenfolgen maskieren.
Ein kalter Request reserviert vor jeder Ableitung atomar das HMAC-Budget für die
vollständige Profilzahl der ausgewählten Gruppe. Bei Erschöpfung folgt sofort
HTTP 503 mit no-store, ohne Warteschlange oder Teilscan. Ein Request verwendet
seine Tabelle sowohl zur Vermeidung von Credential-Lecks als auch zur Bridge-
Authentifizierung. Cachetreffer vermeiden die Ableitung. Authentifizierte Carrier
umgehen Capability-Tabellencache und Ableitung vollständig. Die Fast-Track-Modi
Off/Shadow/Enforce steuern weiterhin die Authentifizierung am Basis-Root;
fehlplatzierte Zugangsdaten des aktuellen Hosts bleiben in jedem Modus lokal.
Nur eine erfolgreiche Bootstrap-Ausgabe für Bridge/Recovery füllt den FIFO-Cache.
`cache_hosts = 0` deaktiviert die Speicherung. Eintrags- und Byteobergrenzen sind
unabhängig; verdrängte Einträge belasten das Bytebudget weiter, solange ein Request
sie referenziert. Ein fehlgeschlagener Cacheeintrag verwirft keinen gültigen
Bootstrap, und Verdrängung setzt keine Quoten zurück. Cacheschlüssel enthalten die
eindeutige ID des unveränderlichen WEB-Snapshots, auch bei Reloads innerhalb
derselben Runtime-Generation. Einträge halten weder Decoy noch Generation fest.
`max_vhosts` zählt exakte Einträge; `max_profiles` zählt exakte Bindungen sowie einen
gemeinsamen Profilsatz je Wildcard-Quellgruppe. `max_rules` begrenzt Muster und
`max_profiles_per_request` den vollständigen Scan einer Wildcard-Gruppe. Außer
`cache_hosts` müssen die Limits positiv sein; der HMAC-Burst muss eine vollständige
Request-Tabelle abdecken. Geprüfte Speicherreservierungen umfassen Vorlagen/Regeln,
Cache, Arbeitsspeicher der Handler und lebende Hostbindungen nur bei aktivem
Wildcard-Modus. Bei ansonsten standardmäßigen Limits reicht der bisherige Rahmen
von 1280 MiB nicht aus; 1290 MiB genügen nach aktueller Berechnung, das Beispiel
sieht 1536 MiB vor. Der Speicherrahmen und die Verarbeitung bei ausschließlich
exakten Hosts bleiben unverändert.
Der Aktivierungsparameter und alle `web.limits` erfordern einen Prozessneustart.
Nach der Aktivierung lassen sich Selektoren und Profile per Reload ändern. Ein
API-Update kann den Parameter und ausreichende Limits als zurückgestellte
Änderungen speichern. Muster vor dem tatsächlichen Neustart hinzuzufügen wird
atomar abgewiesen, auch wenn der Parameter bereits in der gewünschten Konfiguration
steht. Zum Deaktivieren ersetzen Sie zuerst Muster durch exakte Selektoren und
starten dann mit deaktiviertem Parameter neu. Vor einem Downgrade entfernen Sie
Wildcard-Selektoren, den neuen Parameter und die Limittabelle.
## Serverseitige Carrier-Negotiation
Bei `websocket-lanes` löst eine Ablehnung oder ein Timeout vor dem Upgrade einer Lane die gemeinsame Sitzungswiederherstellung aus. Fehler nach dem Upgrade bleiben auf die Lane begrenzt. Dieses Protokollverhalten belegt keine native macOS-/iOS-Kompatibilität bei Rückkehr aus dem Hintergrund.
Die unveränderliche Bridge-Grundstruktur wird gecacht; Nonce, Bootstrap, Host und Basispfad werden für jede Antwort frisch eingesetzt. Ablaufprüfungen nutzen konservative Hinweise auf Deadlines, ohne Ablaufgrenzen zu verlängern. Diese internen Optimierungen ändern weder Wire-Formate, Zulassungslimits noch konfigurierte Timeouts und belegen allein keine kürzere Ende-zu-Ende-Verbindungszeit.
Auto-Negotiation ist optional und bleibt deaktiviert, solange `carriers` nicht als explizites, nicht leeres Array gesetzt ist. Der konfigurierte `carrier` bleibt der letzte Fallback und wird genau einmal angehängt, auch wenn er bereits im Array steht:
```toml
@@ -175,7 +344,9 @@ Jeder Authentifizierungs-, Shape-, Lane-Reservierungs- oder Kapazitätsfehler vo
Der WEB-Listener muss `proxy_protocol = false` und `reuse_allow = false` verwenden. `client_mss`, `synlimit`, `announce` und `announce_ip` sind nicht zulässig. `web_trusted_proxy_cidrs` muss nicht leer sein und darf nur die unmittelbar vorgeschalteten NGINX- oder HAProxy-Peers enthalten; `/0`-Netze werden abgelehnt.
Der HTTP-Decoy-Origin muss eine Loopback-, Link-Local- oder private IP-Adresse als Literal verwenden. Telemt bewahrt bei gewöhnlichen Requests Methode, Pfad, Query, Header, gestreamten Body, Response-Status, Header und Body und entfernt Hop-by-Hop-Header. Vor dem Fallback auf den Decoy entfernt Telemt Carrier-Zugangsdaten und Bodys aus fehlerhaften Carrier-Requests. Ein literaler Decoy-Endpunkt, der exakt einem effektiven WEB-Listener entspricht oder auf demselben Port von dessen gleichfamiliärer Wildcard-Adresse erfasst wird, wird abgelehnt. Indirekte Schleifen über DNS, NGINX, HAProxy oder eine andere Weiterleitungsschicht sind aus der Telemt-Konfiguration nicht beweisbar und müssen betrieblich ausgeschlossen werden.
Für `http_upstream` akzeptiert `resolve` die Werte `"never"` (Standard) und `"startup"`. Standardmäßig ist ein Loopback-, Link-Local- oder privates IP-Literal erforderlich. `startup` erlaubt zusätzlich DNS-Namen: Die asynchrone Konfigurationsvorbereitung löst jedes eindeutige Host-/Portpaar auf, prüft alle Antworten gegen erlaubte Adressklassen und effektive WEB-Listener und fixiert die erste Adresse in Resolver-Reihenfolge. Fehler, leere Antworten, öffentliche Adressen oder direkte Listener-Schleifen verwerfen die Vorbereitung. Der konfigurierte Hostname bleibt in der Upstream-Authority erhalten. Es gibt weder DNS während der Request-Verarbeitung noch automatischen Wechsel zu weiteren Antworten; Reload erstellt einen frischen Snapshot. `web.timeouts.decoy_resolve_secs` begrenzt jede DNS-Abfrage für ein eindeutiges Host-/Portpaar. Die Abfragen laufen nacheinander, ohne gemeinsame Deadline für die gesamte Vorbereitung. Indirekte Schleifen über weitere Weiterleitungsschichten müssen Betreiber ausschließen.
Gewöhnliche Requests behalten Methode, Pfad, Query, Header, gestreamten Body sowie Response-Status und Body, außer Hop-by-Hop-Headern. Fehlerhafte Carrier-Requests verlieren vor der Decoy-Weiterleitung Zugangsdaten und Bodys.
Alternativ kann ein unveränderlicher Snapshot einer statischen Site verwendet werden:
@@ -307,7 +478,7 @@ proxy.example.com {
}
handle {
# gewöhnliche Site
# ordinary site
}
}
```
@@ -335,7 +506,7 @@ Tragen Sie in `web_trusted_proxy_cidrs` die Adresse ein, von der aus Caddy Telem
| Konfiguration | Runtime-Verhalten |
| --- | --- |
| Bestand der WEB-Listener, Bind-Adresse und Vertrauensrichtlinie | Prozesseigen; Telemt neu starten. |
| Jeder Wert in `[web.limits]` | Prozesseigener Speicher- und Ressourcenvertrag; Telemt neu starten. |
| `web.allow_wildcard_hosts` und jeder Wert in `[web.limits]` | Prozesseigener Speicher- und Ressourcenvertrag; Telemt neu starten. |
| `web.enabled`, Carrier-/Negotiation-Richtlinie, `web.debug`, Timeouts, vhosts, Profile und Decoys | Werden vom Config-Watcher oder durch einen Runtime-Generations-Reload angewendet. |
| Änderung des `base_path` eines vhost | Schaltet Routing neuer HTTP-Requests und Capability-Ableitung atomar um. Geben Sie den generierten Link neu aus. Bereits hochgestufte WebSockets und laufende geroutete Austauschvorgänge laufen weiter. Spätere Requests an die alte Basis mit einem prozessauthentischen Bootstrap- oder Session-Token erhalten ein lokales, nicht cachebares `404`; die nun inaktive alte Capability folgt der gewöhnlichen Decoy-Behandlung. Ein bestehender Session-Bearer bleibt nur an der neuen exakten Basis verwendbar, während ein für die alte Capability ausgegebener ungenutzter Bootstrap an der neuen Basis keine Sitzung erstellen kann. |
| Operator-Pause/-Drain-Zustand | Prozesseigen und flüchtig; übersteht einen Generations-Reload, schreibt niemals Konfiguration und wird nach einem Prozessneustart auf `running` zurückgesetzt. |
@@ -356,7 +527,7 @@ WEB-Konfiguration, Runtime-Status und begrenzte Runtime-Steuerung verwenden dens
| Operation | API-Unterstützung |
| --- | --- |
| `[web]`, vhosts, Profile, Decoys, Timeouts oder Limits lesen oder ändern | Ja, über `GET` oder `PATCH /v1/config`. Der abgeleitete Snapshot `web.runtime` wird weder ausgegeben noch kann er geschrieben werden. Verschachtelte Tabellen werden feldweise zusammengeführt; Arrays ersetzen das bisherige Array vollständig. Jede Änderung an `[web.limits]` wird als gewünschte Konfiguration angenommen, aber bis zum Prozessneustart als zurückgestellt gemeldet. |
| `[web]`, vhosts, Profile, Decoys, Timeouts oder Limits lesen oder ändern | Ja, über `GET` oder `PATCH /v1/config`. Der abgeleitete Snapshot `web.runtime` wird weder ausgegeben noch kann er geschrieben werden. Verschachtelte Tabellen werden feldweise zusammengeführt; Arrays ersetzen das bisherige Array vollständig. Änderungen an `web.allow_wildcard_hosts` und `[web.limits]` bleiben bis zum Prozessneustart zurückgestellt. Muster setzen einen bereits aktivierten Wildcard-Modus im laufenden Prozess voraus. |
| `server.listeners` speichern | Ja, über `PATCH /v1/config`; ein geänderter WEB-Listener bleibt jedoch bis zum Prozessneustart zurückgestellt. |
| Außerhalb der API geänderte WEB-Konfiguration anwenden | Ja, über `POST /v1/system/reload` und anschließende Abfrage des Vorgangsstatus. |
| Begrenzte serverseitige WEB-Request- und Lifecycle-Details untersuchen | Ja, über ein authentifiziertes `GET /web-status`. |
@@ -441,7 +612,7 @@ curl -sS http://127.0.0.1:9091/v1/system/reload/RELOAD_ID \
-H "Authorization: ${TELEMT_API_AUTH}"
```
Der terminale Status `succeeded` bestätigt die Runtime-Aktivierung. Geänderte Carrier-, Kandidaten-, Deadline- oder Learning-Richtlinien werden von neu ausgegebenen Bridge-Sitzungen verwendet; bestehende Sitzungen und laufende Versuchsketten werden nicht migriert. Enthält `deferred_process_fields` den Wert `server.listeners` oder `web.limits`, ist die Datei gültig und gespeichert, diese Einstellungen erfordern aber weiterhin einen Telemt-Neustart.
Der terminale Status `succeeded` bestätigt die Runtime-Aktivierung. Geänderte Carrier-, Kandidaten-, Deadline- oder Learning-Richtlinien werden von neu ausgegebenen Bridge-Sitzungen verwendet; bestehende Sitzungen und laufende Versuchsketten werden nicht migriert. Enthält `deferred_process_fields` den Wert `server.listeners`, `web.allow_wildcard_hosts` oder `web.limits`, ist die Datei gültig und gespeichert, diese Einstellungen erfordern aber weiterhin einen Telemt-Neustart.
Operationen für Access-Benutzer verwenden die vorhandenen Endpunkte, zum Beispiel:
@@ -485,7 +656,7 @@ Der vollständige Vertrag für Requests, Revisionen, Fehler und alle Benutzer-En
| Symptom | Prüfung |
| --- | --- |
| WEB-Konfiguration ist auf dem Datenträger gültig, aber das Listener-Verhalten hat sich nicht geändert | Prüfen Sie `deferred_process_fields`; Listener- und `[web.limits]`-Änderungen erfordern einen Neustart. |
| WEB-Konfiguration ist auf dem Datenträger gültig, aber das Listener-Verhalten hat sich nicht geändert | Prüfen Sie `deferred_process_fields`; Listener- und `web.allow_wildcard_hosts` / `[web.limits]`-Änderungen erfordern einen Neustart. |
| Carrier-Requests erreichen den Decoy | Prüfen Sie den exakten vhost, den Secret-Modus des Links, das CIDR des direkten Proxys und genau einen syntaktisch gültigen `X-Forwarded-For`-Wert. |
| Ein Link funktioniert nach einer Änderung von `base_path` nicht mehr | Importieren Sie den neu ausgegebenen Pfad-Link und prüfen Sie, dass das vollständige neue Präfix Telemt unverändert erreicht. Bestehende Sitzungen können sich nur über die neue exakte Basis wiederherstellen; alte Capabilities sind nicht wiederverwendbar. |
| `/telegram/web` leitet auf `/telegram/web/` um | Fügen Sie für den Pfad ohne Schrägstrich einen exakten Non-WEB-Handler hinzu. Nur der mit Schrägstrich abgeschlossene konfigurierte Teilbaum gehört zum WEB-Vertrag von Telemt. |
+170 -6
View File
@@ -115,8 +115,170 @@ max_streams_per_session = 64
`decoy_fasttrack_mode` управляет только capability processing для `GET/HEAD` на настроенном base root. Значение `off` по умолчанию сохраняет полный прежний scan без fast-track counters. `shadow` учитывает, какие структурно невозможные запросы могли бы обойти scan, но всё равно выполняет его полностью. `enforce` обходит capability work только для `HEAD` либо отсутствующего или неканонического query `bridge`. Каждый точный канонический bridge GET на base root выполняет полный scan всех профилей выбранного vhost и при совпадении, и при промахе. Настройка требует перезапуска процесса: reload сохраняет желаемое значение, но сообщает `web.decoy_fasttrack_mode` как deferred. Fast-track не защищает от злонамеренной CPU-нагрузки, потому что scanner всегда может отправлять канонические candidates; кроме того, `enforce` может создать публично наблюдаемый timing class формы запроса, особенно при статическом decoy. Не включайте этот режим без внешних timing measurements через production TLS-терминатор.
## Общие профили для нескольких доменов
Замените селектор `host` непустым списком `hosts`, чтобы несколько доменов
использовали общие определения профилей и один снимок decoy:
```toml
[[web.vhosts]]
hosts = ["proxy.example.com", "backup.example.com"]
base_path = "telegram/web"
public_addr = "203.0.113.10:443"
[web.vhosts.decoy]
mode = "http_upstream"
upstream = "http://127.0.0.1:18081"
[[web.vhosts.profiles]]
user = "web-user"
secret_mode = "dd"
max_sessions = 8
max_streams = 512
max_streams_per_session = 64
```
Этот фрагмент дополняет пользователя доступа и WEB listener из предыдущего
примера. Укажите ровно один селектор: `host` или `hosts`. При загрузке имена
нормализуются; совпадающие после нормализации имена запрещены. Шаблоны wildcard
и `*` требуют явного включения режима, описанного ниже. У всех доменов группы
общие `base_path`, `public_addr`, профили и decoy. Если эти настройки различаются,
создайте отдельные группы. TLS-терминатор должен обслуживать каждый домен из
списка и передавать исходный канонический `Host`.
У каждого домена свои capability, bootstrap/session credentials и квота профиля.
В примере профиль допускает до восьми сессий на каждом домене с учётом общих
ограничений процесса, IP и пользователя доступа. При запуске ссылки формируются
отдельно для каждого выбранного пользователя/профиля и конкретного домена.
Группировка не перенаправляет клиентов и не позволяет переносить credentials
между доменами.
В режиме точных имён `max_vhosts` учитывает каждый домен, а `max_profiles` —
каждую пару домен/профиль. Для восьми доменов со 100 профилями нужны пределы
не менее восьми vhosts и 800 profiles. Статические файлы и байты снимка одной
группы учитываются один раз; у отдельных групп снимки отдельные. Настроенные
максимумы сессий не резервируют сессии заранее. Общая неизменяемая политика
уменьшает дублирование, но индексы capability растут с числом пар домен/профиль.
Сначала установите новую сборку с прежней конфигурацией одиночных `host`, затем
объедините одинаково настроенные записи через reload. Группировка и перестановка
доменов сохраняют совместимые bootstrap credentials, идентичность квот и данные
обучения профиля. Удаление домена запрещает новые запросы к нему, не вводя новых
правил завершения существующих соединений. Увеличение лимитов требует перезапуска
и должно вступить в силу до добавления записей сверх действующих пределов.
Перед откатом на сборку без поддержки `hosts` разверните группы в одиночные
записи `host` и повторно проверьте бюджет статических снимков.
## Wildcard-хосты
По умолчанию используются точные `host` / `hosts`. Для произвольных поддоменов
установите `web.allow_wildcard_hosts = true` и перезапустите Telemt. После этого
селекторы также принимают `*.example.com` и `*`; точные имена и шаблоны можно
смешивать в одном списке:
```toml
[web]
enabled = true
allow_wildcard_hosts = true
[web.limits]
# Additional wildcard reservations must fit the declared envelope.
memory_envelope_bytes = 1610612736
[web.limits.wildcard]
max_rules = 32
max_profiles_per_request = 256
cache_hosts = 256
cache_bytes = 8388608
cold_hmac_per_minute = 1000000
cold_hmac_burst = 65536
[[web.vhosts]]
hosts = ["proxy.example.com", "*.example.com"]
base_path = "relay"
public_addr = "203.0.113.10:443"
[web.vhosts.decoy]
mode = "http_upstream"
upstream = "http://127.0.0.1:8080"
[[web.vhosts.profiles]]
user = "web-user"
secret_mode = "dd"
```
Этот пример дополняет ранее показанные listener и пользователя доступа. Запрос
выбирает одну группу: сначала точное имя, затем самый длинный подходящий суффикс,
затем `*`. Суффикс охватывает потомков любой глубины, включая `a.b.example.com`,
но не сам `example.com`. Неуспешная аутентификация не переключает запрос на
другое правило. Встроенные wildcard и регулярные выражения запрещены, как и
дубли селекторов после нормализации между группами. Выбранная группа сохраняет
свои фиксированные `public_addr`, базовый путь, профили и decoy. Заголовок Host
не выбирает адрес upstream.
В этом режиме HTTP Host нормализуется без учёта регистра ASCII; удаляется только
необязательный буквальный порт `:443`. Повторные Host, IP-адреса вместо домена,
некорректные DNS/ACE-метки, завершающая точка и другие порты запрещены.
`X-Forwarded-Host` не используется. Capability вычисляется по фактическому
каноническому имени с существующим клиентским алгоритмом; менять клиентов не
нужно. Квоты сессий/потоков/профиля остаются привязаны к конкретной тройке
`(host, user, secret_mode)`. Ограничения процесса, IP и пользователя доступа
продолжают действовать. Ссылки при запуске выводятся только для точных имён.
Frontend **обязан ограничивать допустимые Host**, а незашифрованный WEB backend
должен оставаться в закрытой сети. Сертификаты TLS должны покрывать каждое
фактическое имя клиента. Это явная граница безопасности: capability неизвестного
или вытесненного из кэша wildcard-домена, отправленная на другой домен, может
попасть в его decoy, в том числе на точный домен смешанной конфигурации.
Capability текущего домена, конечного списка точных доменов, известного
положительного кэша и подлинные bootstrap/session tokens процесса не передаются
в decoy в URI и заголовках, включая percent-encoded формы. Публичные URL, cookies
и заголовки не отклоняются лишь за сходство с credentials. Диагностические копии,
напротив, консервативно маскируют похожие строки, включая обрезанные префиксы;
байты публичных запросов/ответов и исходные хеши User-Agent не меняются. Поэтому
диагностика может маскировать и обычные длинные строки.
Перед вычислениями холодный запрос атомарно резервирует HMAC-бюджет для всех
профилей выбранной группы. При нехватке сразу возвращается HTTP 503 с no-store,
без очереди и частичного перебора. В пределах запроса одна таблица используется
для защиты от утечки credentials и аутентификации bridge. Попадание в кэш не
требует вычислений. Аутентифицированные carriers полностью обходят кэш таблиц
capability и их вычисление. Режимы fast-track Off/Shadow/Enforce по-прежнему
управляют проверкой корня; ошибочно размещённые credentials текущего домена
удерживаются локально в любом режиме.
FIFO-кэш заполняется только после успешной выдачи bootstrap для bridge/recovery.
`cache_hosts = 0` отключает хранение. Пределы количества записей и байтов независимы;
вытесненная запись продолжает занимать байтовый бюджет, пока запрос удерживает
ссылку на неё. Неудача вставки не отменяет корректный bootstrap; вытеснение не
сбрасывает квоты. Ключ кэша содержит уникальный идентификатор неизменяемого WEB
снимка, в том числе при reload внутри одного поколения runtime. Записи не
удерживают decoy или поколение runtime.
`max_vhosts` учитывает точные имена; `max_profiles` — точные привязки и один
общий набор профилей на каждую группу с wildcard. `max_rules` ограничивает число
шаблонов, а `max_profiles_per_request` — полный перебор группы wildcard. Все
пределы, кроме `cache_hosts`, должны быть положительными; HMAC burst должен
вмещать полную таблицу запроса. Проверяемый бюджет памяти включает шаблоны/правила,
кэш, рабочую память обработчиков и живые привязки доменов только при включённом
wildcard. С остальными стандартными лимитами прежних 1280 MiB недостаточно;
1290 MiB достаточно по текущему расчёту, а пример задаёт 1536 MiB. Бюджет и
обработка режима только с точными именами не меняются.
Флаг включения и все `web.limits` требуют перезапуска. После включения селекторы
и профили можно менять через reload. API может сохранить флаг и достаточные
лимиты как отложенные изменения. Добавление шаблонов до фактического перезапуска
отклоняется атомарно, даже если флаг уже записан в желаемой конфигурации. Для
отключения сначала замените шаблоны точными именами, затем перезапустите процесс
с выключенным флагом. Перед откатом на старую сборку удалите wildcard-селекторы,
новый флаг и таблицу лимитов.
## Server-side negotiation carrier
Для `websocket-lanes` отказ или таймаут до Upgrade отдельной lane запускает общее восстановление сессии. Сбой после Upgrade остаётся локальным для lane. Это свойство протокола не подтверждает совместимость восстановления нативных macOS/iOS клиентов после фонового режима.
Неизменяемая основа bridge кэшируется, а nonce, bootstrap, host и base path подставляются заново для каждого ответа. Обработка истечения сроков использует консервативные оценки ближайших сроков, не продлевая сроки. Эти внутренние оптимизации не меняют форматы протокола, лимиты приёма или таймауты и сами по себе не доказывают сокращения полного времени подключения.
Auto-negotiation необязателен и выключен, пока `carriers` не задан явным непустым массивом. Настроенный `carrier` остаётся последним fallback и добавляется ровно один раз, даже если уже присутствует в массиве:
```toml
@@ -175,7 +337,9 @@ WebSocket codec buffers и находящиеся в обработке read/wri
Для WEB-listener обязательны `proxy_protocol = false` и `reuse_allow = false`. В нём нельзя использовать `client_mss`, `synlimit`, `announce` и `announce_ip`. Массив `web_trusted_proxy_cidrs` должен быть непустым и содержать только непосредственные адреса NGINX или HAProxy; сети `/0` запрещены.
HTTP decoy origin должен быть loopback, link-local или private IP literal. Для обычных запросов Telemt сохраняет method, path, query, headers, streamed body, response status, headers и body, удаляя hop-by-hop headers. Перед отправкой некорректного carrier-запроса в decoy Telemt удаляет из него carrier credentials и body. Literal decoy endpoint отклоняется, если он точно совпадает с effective WEB-listener либо покрывается wildcard address того же IP-семейства на том же порту. Косвенные loops через DNS, NGINX, HAProxy или другой forwarding layer нельзя доказать из конфигурации Telemt; оператор обязан исключить их самостоятельно.
Для `http_upstream` параметр `resolve` принимает `"never"` (по умолчанию) или `"startup"`. По умолчанию нужен IP-адрес из loopback, link-local или private диапазона. `startup` также разрешает DNS-имена: асинхронная подготовка конфигурации разрешает каждую уникальную пару имя/порт, проверяет все ответы по допустимым классам адресов и действующим WEB listeners и закрепляет первый адрес в порядке ответа resolver. Ошибка, пустой ответ, публичный адрес или прямая петля к listener отклоняют подготовку. В upstream authority сохраняется настроенное имя. DNS при обработке запросов и автоматического перехода к другим ответам нет; reload готовит новый снимок. `web.timeouts.decoy_resolve_secs` ограничивает отдельный DNS-запрос для каждой уникальной пары имя/порт. Запросы выполняются последовательно, общего таймаута подготовки нет. Косвенные петли через другие прокси оператор должен исключить самостоятельно.
В обычных запросах сохраняются метод, путь, query, заголовки, потоковое тело, статус и тело ответа, кроме hop-by-hop заголовков. Из некорректных carrier-запросов перед передачей в decoy удаляются credentials и тело.
Вместо origin можно использовать immutable snapshot статического сайта:
@@ -307,7 +471,7 @@ proxy.example.com {
}
handle {
# обычный сайт
# ordinary site
}
}
```
@@ -335,7 +499,7 @@ log {
| Конфигурация | Поведение runtime |
| --- | --- |
| Состав WEB-listeners, bind address и trust policy | Принадлежат процессу; перезапустите Telemt. |
| Любое значение `[web.limits]` | Process-owned контракт памяти и ресурсов; перезапустите Telemt. |
| `web.allow_wildcard_hosts` и любое значение `[web.limits]` | Process-owned контракт памяти и ресурсов; перезапустите Telemt. |
| `web.enabled`, policy carrier/negotiation, `web.debug`, timeouts, vhosts, profiles и decoys | Применяются config watcher или runtime generation reload. |
| Изменение `base_path` vhost | Атомарно переключает маршрутизацию новых HTTP-запросов и derivation capability. Выпустите новую сгенерированную ссылку. Уже upgraded WebSockets и начатые маршрутизированные обмены продолжаются. Последующие запросы к старому base с подлинным для процесса bootstrap- или session-token получают локальный no-store `404`, а ставшая неактивной прежняя capability обрабатывается как обычный decoy traffic. Существующий session bearer остаётся пригодным только на новом точном base, а неиспользованный bootstrap, выданный для старой capability, не может создать session на новом base. |
| Operator pause/drain state | Process-owned и ephemeral; переживает generation reload, никогда не записывает конфигурацию и после перезапуска процесса возвращается в `running`. |
@@ -356,7 +520,7 @@ HTTP idle accounting защищает только явно ограниченн
| Операция | Поддержка API |
| --- | --- |
| Чтение или изменение `[web]`, vhosts, profiles, decoys, timeouts или limits | Да, через `GET` или `PATCH /v1/config`. Производный snapshot `web.runtime` не возвращается и недоступен для записи. Вложенные tables сливаются по полям; arrays целиком заменяют прежний array. Любое изменение `[web.limits]` принимается как desired configuration, но помечается deferred до перезапуска процесса. |
| Чтение или изменение `[web]`, vhosts, profiles, decoys, timeouts или limits | Да, через `GET` или `PATCH /v1/config`. Производный snapshot `web.runtime` не возвращается и недоступен для записи. Вложенные tables сливаются по полям; arrays целиком заменяют прежний array. Изменения `web.allow_wildcard_hosts` и `[web.limits]` откладываются до перезапуска процесса. Добавлять шаблоны можно только после включения wildcard в действующем процессе. |
| Сохранение `server.listeners` | Да, через `PATCH /v1/config`, но изменённый WEB-listener остаётся deferred до перезапуска процесса. |
| Применение WEB-конфигурации, изменённой вне API | Да, через `POST /v1/system/reload` с последующей проверкой статуса операции. |
| Просмотр bounded серверных WEB request- и lifecycle-деталей | Да, через аутентифицированный `GET /web-status`. |
@@ -441,7 +605,7 @@ curl -sS http://127.0.0.1:9091/v1/system/reload/RELOAD_ID \
-H "Authorization: ${TELEMT_API_AUTH}"
```
Терминальный статус `succeeded` подтверждает активацию runtime. Изменённые carrier, candidates, deadlines или learning policy используют новые bridge sessions; существующие сессии и начатые attempt chains не мигрируют. Если `deferred_process_fields` содержит `server.listeners` или `web.limits`, файл валиден и сохранён, но эти настройки всё ещё требуют перезапуска Telemt.
Терминальный статус `succeeded` подтверждает активацию runtime. Изменённые carrier, candidates, deadlines или learning policy используют новые bridge sessions; существующие сессии и начатые attempt chains не мигрируют. Если `deferred_process_fields` содержит `server.listeners`, `web.allow_wildcard_hosts` или `web.limits`, файл валиден и сохранён, но эти настройки всё ещё требуют перезапуска Telemt.
Операции с access users используют существующие endpoints, например:
@@ -485,7 +649,7 @@ curl -sS -X POST http://127.0.0.1:9091/v1/users/web-user/rotate-secret \
| Симптом | Что проверить |
| --- | --- |
| WEB-конфигурация валидна на диске, но поведение listener’а не изменилось | Проверьте `deferred_process_fields`; listener и `[web.limits]` требуют перезапуска. |
| WEB-конфигурация валидна на диске, но поведение listener’а не изменилось | Проверьте `deferred_process_fields`; listener и `web.allow_wildcard_hosts` / `[web.limits]` требуют перезапуска. |
| Carrier-запросы попадают в decoy | Проверьте точный vhost, secret mode ссылки, CIDR непосредственного proxy и единственное корректно разбираемое значение `X-Forwarded-For`. |
| Ссылка перестала работать после изменения `base_path` | Импортируйте заново напечатанную path-ссылку и убедитесь, что полный новый prefix без изменений попадает в Telemt. Существующие sessions могут восстановиться только через новый точный base; старые capabilities нельзя использовать повторно. |
| `/telegram/web` перенаправляет на `/telegram/web/` | Добавьте точный non-WEB handler для path без слеша. В WEB-контракт Telemt входит только настроенное поддерево с завершающим слешем. |