Kaynağa Gözat

Merge 5d9a5efb8f into 8d143d7bde

pull/478/merge
Alexey Dolotov 3 gün önce
ebeveyn
işleme
4441fe5288
No account linked to committer's email address

+ 40
- 3
contrib/sni-router/README.md Dosyayı Görüntüle

@@ -47,15 +47,52 @@ docker compose exec mtg mtg access /config/config.toml
47 47
 
48 48
 HAProxy forwards TCP connections to mtg and Caddy with a PROXY protocol
49 49
 v2 header so both backends see the real client IP instead of HAProxy's
50
-container address.  The three pieces must stay in sync:
50
+container address.  Caddy also receives PROXY v2 from mtg on the
51
+fronting path (see "Fronting loop" below), so all four pieces below
52
+must stay in sync:
51 53
 
52 54
 - `haproxy.cfg` — `send-proxy-v2` on the `mtg` and `web` backend `server` lines
53
-- `mtg-config.toml` — `proxy-protocol-listener = true`
55
+- `mtg-config.toml` — `proxy-protocol-listener = true` (HAProxy → mtg)
56
+- `mtg-config.toml` — `[domain-fronting].proxy-protocol = true` (mtg → Caddy on fronting)
54 57
 - `Caddyfile` — `listener_wrappers { proxy_protocol { ... } tls }` on `:8443`
55 58
 
56
-If you disable one, disable all three, otherwise the backend will fail
59
+If you disable one, disable all four, otherwise the backend will fail
57 60
 to parse the connection.
58 61
 
62
+## Fronting loop (why `[domain-fronting]` is set explicitly)
63
+
64
+When mtg sees TLS that isn't valid Telegram (a probe or a browser
65
+hitting the domain on `:443`), it forwards that connection to a real
66
+web server — "domain fronting".  By default mtg uses the secret's
67
+hostname as the fronting target and resolves it via DNS, which in
68
+this setup points back to this server: the fronting dial lands on
69
+HAProxy, SNI matches the secret, HAProxy routes the connection back
70
+to mtg → loop.
71
+
72
+The trigger is DNS, not name equality: any time the secret's hostname
73
+resolves to this host, the loop reproduces.  In an SNI-router
74
+deployment the secret's hostname has to point here for clients to
75
+reach mtg in the first place, so the loop is the default state unless
76
+mtg is steered away from HAProxy.
77
+
78
+`mtg-config.toml` therefore pins the fronting target to the Caddy
79
+container directly:
80
+
81
+```toml
82
+[domain-fronting]
83
+host = "web"
84
+port = 8443
85
+proxy-protocol = true
86
+```
87
+
88
+`host = "web"` resolves through compose-network DNS to the `web`
89
+service (Caddy), bypassing HAProxy.  `proxy-protocol = true` matches
90
+Caddy's `:8443` listener wrapper so the real client IP still
91
+propagates to Caddy's logs.
92
+
93
+Requires mtg ≥ 2.4 — hostname acceptance for the fronting target was
94
+added in #480.
95
+
59 96
 ## ACME (Let's Encrypt) notes
60 97
 
61 98
 HAProxy passes `/.well-known/acme-challenge/` requests on `:80` to

+ 11
- 0
contrib/sni-router/mtg-config.toml Dosyayı Görüntüle

@@ -11,6 +11,17 @@ bind-to = "0.0.0.0:3128"
11 11
 # real client IP.  Keep this in sync with haproxy.cfg (`send-proxy-v2`).
12 12
 proxy-protocol-listener = true
13 13
 
14
+# Fronting target: point mtg at the Caddy container directly so its
15
+# fallback dial (for non-Telegram TLS) bypasses HAProxy and doesn't
16
+# loop back here.  Without this, mtg resolves the secret's hostname
17
+# via DNS, which in this setup resolves to this server -> HAProxy ->
18
+# mtg again.  See README's "Fronting loop" section for the long form.
19
+# Requires mtg >= 2.4 (#480 added hostname acceptance for the target).
20
+[domain-fronting]
21
+host = "web"
22
+port = 8443
23
+proxy-protocol = true
24
+
14 25
 [defense.anti-replay]
15 26
 enabled = true
16 27
 max-size = "1mib"

Loading…
İptal
Kaydet