瀏覽代碼

sni-router: review fixups (concise comments, accurate v6only note, narrow Caddy allow)

- Caddy allow: 127.0.0.0/8 → 127.0.0.1/32 (only loopback peer is HAProxy).
- haproxy.cfg: rewrite v6only comment to describe what it actually does
  (suppresses v4-mapped accept, preventing conflict with the v4 bind),
  not the symptom.
- docker-compose.yml: trim the 8-line haproxy comment to 3 lines and
  defer the rationale to README.  Add one-line note explaining why web
  uses host port 8080 (HAProxy owns :80).
- README: condense the "Why network_mode: host" subsection.  Spell out
  trade-offs as a list: own-the-host-ports, Linux-only (Docker Desktop
  doesn't make this layout reachable), userns-remap incompatibility.
  Note that mtg-config.toml stays as-is because mtg/web remain on the
  compose bridge.
pull/522/head
Alexey Dolotov 2 月之前
父節點
當前提交
b083d75731
共有 4 個文件被更改,包括 30 次插入31 次删除
  1. 2
    2
      contrib/sni-router/Caddyfile
  2. 20
    17
      contrib/sni-router/README.md
  3. 5
    10
      contrib/sni-router/docker-compose.yml
  4. 3
    2
      contrib/sni-router/haproxy.cfg

+ 2
- 2
contrib/sni-router/Caddyfile 查看文件

@@ -11,7 +11,7 @@
11 11
 	# is terminated on the unwrapped connection.
12 12
 	#
13 13
 	# `allow` lists the networks permitted to send PROXY headers.
14
-	# 127.0.0.0/8 covers HAProxy reaching Caddy over host loopback (HAProxy
14
+	# 127.0.0.1/32 covers HAProxy reaching Caddy over host loopback (HAProxy
15 15
 	# runs in network_mode: host and connects to the published 127.0.0.1
16 16
 	# port).  The RFC1918 ranges cover mtg → Caddy on the compose bridge
17 17
 	# (fronting path; see "Fronting loop" in README.md).
@@ -19,7 +19,7 @@
19 19
 		listener_wrappers {
20 20
 			proxy_protocol {
21 21
 				timeout 5s
22
-				allow 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
22
+				allow 127.0.0.1/32 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
23 23
 			}
24 24
 			tls
25 25
 		}

+ 20
- 17
contrib/sni-router/README.md 查看文件

@@ -65,23 +65,26 @@ to parse the connection.
65 65
 
66 66
 ### Why HAProxy uses `network_mode: host`
67 67
 
68
-When a container is on a bridge network and a port is published with
69
-`ports: "443:443"`, the source IP of inbound connections is rewritten
70
-to the bridge gateway before HAProxy sees it — Docker's `docker-proxy`
71
-userland forwarder accepts on the host and re-opens the connection
72
-from the gateway; Podman's `slirp4netns` / `pasta` does the same in
73
-rootless mode.  The PROXY v2 header HAProxy then sends downstream
74
-carries that gateway address (e.g. `172.x.x.1`), not the real client.
75
-
76
-`network_mode: host` puts HAProxy in the host network namespace, so it
77
-binds `:443` / `:80` directly with no NAT in the path and observes the
78
-true source address of every connection.  mtg and Caddy stay on the
79
-compose bridge and are published only on `127.0.0.1` — HAProxy reaches
80
-them via host loopback, and the PROXY v2 header carries the real
81
-client IP (v4 or v6) end-to-end.
82
-
83
-Trade-off: HAProxy occupies the host's `:443` and `:80`.  Don't run
84
-anything else on those ports on the same host.
68
+A published port on a bridge network rewrites the source IP of inbound
69
+connections to the bridge gateway before HAProxy sees it (Docker's
70
+`docker-proxy`, Podman's `slirp4netns`/`pasta`), so the PROXY v2 header
71
+HAProxy forwards downstream carries that gateway address, not the real
72
+client.  Host-mode HAProxy binds in the host netns directly, no NAT in
73
+the path, and the rewrite never happens.  mtg and Caddy stay on the
74
+compose bridge and are published on `127.0.0.1` only — HAProxy reaches
75
+them over host loopback.  `mtg-config.toml` does not need to change;
76
+fronting still uses `host = "web"` over compose-network DNS.
77
+
78
+**Trade-offs.**
79
+- HAProxy owns the host's `:443` and `:80` — don't run anything else
80
+  on those ports.
81
+- Linux host only.  On Docker Desktop (macOS/Windows), "host" means
82
+  the Linux VM, not the user's machine, so external clients can't
83
+  reach the proxy.
84
+- If you run Docker with `userns-remap`, the in-container "root"
85
+  loses the privilege to bind `<1024` on the host; either disable
86
+  `userns-remap` for this stack or lower `net.ipv4.ip_unprivileged_port_start`
87
+  on the host.
85 88
 
86 89
 ## Fronting loop (why `[domain-fronting]` is set explicitly)
87 90
 

+ 5
- 10
contrib/sni-router/docker-compose.yml 查看文件

@@ -27,15 +27,9 @@ x-domain-env: &domain-env
27 27
 services:
28 28
   haproxy:
29 29
     image: haproxy:lts-alpine
30
-    # network_mode: host lets HAProxy see real client source IPs (v4 and v6)
31
-    # instead of the docker/podman bridge gateway.  Bridge ingress (docker-proxy
32
-    # userland forwarder, podman slirp4netns/pasta) rewrites the source address
33
-    # of inbound connections to the gateway; with host networking HAProxy binds
34
-    # in the host netns directly and the rewrite never happens.  See the
35
-    # "Real client IPs" section of README.md.
36
-    #
37
-    # Trade-off: HAProxy occupies host :443 and :80.  Don't run anything else
38
-    # on those ports.
30
+    # Host netns so HAProxy sees real client IPs (v4/v6) instead of the
31
+    # bridge gateway address.  Linux host only; see README → "Why HAProxy
32
+    # uses network_mode: host" for the rationale and trade-off.
39 33
     network_mode: host
40 34
     volumes:
41 35
       - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro,Z
@@ -52,7 +46,7 @@ services:
52 46
     volumes:
53 47
       - ./mtg-config.toml:/config/config.toml:ro,Z
54 48
     # Published on host loopback only — HAProxy (host netns) reaches it via
55
-    # 127.0.0.1:3128.  Not exposed on any public interface.
49
+    # 127.0.0.1.
56 50
     ports:
57 51
       - "127.0.0.1:3128:3128"
58 52
     restart: unless-stopped
@@ -66,6 +60,7 @@ services:
66 60
       - caddy_data:/data
67 61
       - ./www:/srv:ro,Z
68 62
     # Published on host loopback only — HAProxy reaches Caddy on 127.0.0.1.
63
+    # Port 8080 (not 80) on the host because HAProxy already owns host :80.
69 64
     ports:
70 65
       - "127.0.0.1:8080:80"
71 66
       - "127.0.0.1:8443:8443"

+ 3
- 2
contrib/sni-router/haproxy.cfg 查看文件

@@ -24,8 +24,9 @@ defaults
24 24
 
25 25
 frontend http
26 26
     # Explicit v4 + v6 binds so IPv6 clients are accepted regardless of the
27
-    # host's IPV6_V6ONLY sysctl.  v6only on the v6 bind avoids the
28
-    # "address in use" overlap on dual-stack hosts.
27
+    # host's net.ipv6.bindv6only sysctl.  `v6only` on the v6 bind prevents it
28
+    # from also accepting v4-mapped connections, which would otherwise
29
+    # conflict with the explicit v4 bind on the same port.
29 30
     bind 0.0.0.0:80
30 31
     bind [::]:80 v6only
31 32
     mode http

Loading…
取消
儲存