From 3178e25e781c5079a1b5909343afe3889fe8282d Mon Sep 17 00:00:00 2001 From: Debian Date: Wed, 13 May 2026 19:28:41 +0200 Subject: [PATCH] feat(haproxy): X-Forwarded-Proto + X-Real-IP an alle Backends weiterleiten MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User-Frage: „Werden via haproxy die echten IPs durchgereicht?". Antwort: X-Forwarded-For ja (option forwardfor), aber Apps wie WordPress/Mailcow brauchen zusätzlich X-Forwarded-Proto=https um Redirect-Loops zu vermeiden, und X-Real-IP ist die bequeme single-value-Variante die viele Tools out-of-the-box lesen (ohne die XFF-Chain parsen zu müssen). Beide Frontends (public_https + mgmt_https) emittieren jetzt: http-request set-header X-Forwarded-Proto https http-request set-header X-Real-IP %[src] Was Backends sehen: X-Forwarded-For: (defaults: option forwardfor) X-Forwarded-Proto: https (NEW) X-Real-IP: (NEW, single value) PROXY-Protocol-Toggle pro Backend kommt nicht in diesem Release — der Operator hat „nur Header-Variante" gewählt. Co-Authored-By: Claude Opus 4.7 (1M context) --- VERSION | 2 +- cmd/edgeguard-api/main.go | 2 +- cmd/edgeguard-ctl/main.go | 2 +- cmd/edgeguard-scheduler/main.go | 2 +- internal/haproxy/haproxy.cfg.tpl | 9 +++++++++ internal/haproxy/haproxy_test.go | 6 ++++++ management-ui/src/components/Layout/Sidebar.tsx | 2 +- 7 files changed, 20 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 5257575..f9ef507 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.77 +1.0.78 diff --git a/cmd/edgeguard-api/main.go b/cmd/edgeguard-api/main.go index af910a3..ba8ca69 100644 --- a/cmd/edgeguard-api/main.go +++ b/cmd/edgeguard-api/main.go @@ -54,7 +54,7 @@ import ( wgsvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/wireguard" ) -var version = "1.0.77" +var version = "1.0.78" func main() { addr := os.Getenv("EDGEGUARD_API_ADDR") diff --git a/cmd/edgeguard-ctl/main.go b/cmd/edgeguard-ctl/main.go index 955bb47..0ca81fc 100644 --- a/cmd/edgeguard-ctl/main.go +++ b/cmd/edgeguard-ctl/main.go @@ -11,7 +11,7 @@ import ( "git.netcell-it.de/projekte/edgeguard-native/internal/services/setup" ) -var version = "1.0.77" +var version = "1.0.78" const usage = `edgeguard-ctl — EdgeGuard CLI diff --git a/cmd/edgeguard-scheduler/main.go b/cmd/edgeguard-scheduler/main.go index 271bc89..da91942 100644 --- a/cmd/edgeguard-scheduler/main.go +++ b/cmd/edgeguard-scheduler/main.go @@ -32,7 +32,7 @@ import ( "git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts" ) -var version = "1.0.77" +var version = "1.0.78" const ( // renewTickInterval — how often we re-evaluate expiring certs. diff --git a/internal/haproxy/haproxy.cfg.tpl b/internal/haproxy/haproxy.cfg.tpl index 9e171df..0668c90 100644 --- a/internal/haproxy/haproxy.cfg.tpl +++ b/internal/haproxy/haproxy.cfg.tpl @@ -53,6 +53,13 @@ frontend public_https http-response set-header Strict-Transport-Security "max-age=31536000" + # Client-IP-Weiterleitung an Backends. `option forwardfor` (defaults) + # setzt X-Forwarded-For; wir ergänzen Proto + RealIP damit Apps + # erkennen können (a) dass der Client HTTPS sprach und (b) die + # echte Source-IP ohne XFF-Chain-Parsing brauchen. + http-request set-header X-Forwarded-Proto https + http-request set-header X-Real-IP %[src] + {{- range $d := .Domains}} {{- range $r := $d.Routes}} use_backend eg_backend_{{$r.BackendID}} if { hdr(host) -i {{$d.Name}} } { path_beg {{$r.PathPrefix}} } @@ -70,6 +77,8 @@ frontend public_https frontend mgmt_https bind :3443 ssl crt /etc/edgeguard/tls/ alpn h2,http/1.1 http-response set-header Strict-Transport-Security "max-age=31536000" + http-request set-header X-Forwarded-Proto https + http-request set-header X-Real-IP %[src] default_backend api_backend # ── Internal stats ───────────────────────────────────────────────────── diff --git a/internal/haproxy/haproxy_test.go b/internal/haproxy/haproxy_test.go index b526817..6552973 100644 --- a/internal/haproxy/haproxy_test.go +++ b/internal/haproxy/haproxy_test.go @@ -43,6 +43,12 @@ func TestRender_BaselineHasFrontendsAndApiBackend(t *testing.T) { "bind :443 ssl crt /etc/edgeguard/tls/", "path_beg /.well-known/acme-challenge/", "http-request redirect scheme https", + // Client-IP-Weiterleitung an Backends — XFF kommt aus + // defaults (option forwardfor), Proto + RealIP setzen wir + // pro public-Frontend explizit. + "option forwardfor", + "http-request set-header X-Forwarded-Proto https", + "http-request set-header X-Real-IP %[src]", } { if !strings.Contains(out, w) { t.Errorf("missing %q in baseline output:\n%s", w, out) diff --git a/management-ui/src/components/Layout/Sidebar.tsx b/management-ui/src/components/Layout/Sidebar.tsx index bf8f61a..c219905 100644 --- a/management-ui/src/components/Layout/Sidebar.tsx +++ b/management-ui/src/components/Layout/Sidebar.tsx @@ -85,7 +85,7 @@ const NAV: NavSection[] = [ }, ] -const VERSION = '1.0.77' +const VERSION = '1.0.78' // Sidebar-Pattern 1:1 aus netcell-webpanel (enconf) übernommen: // -