From 92eece936dd98acec0d949067713cadc889fc9b5 Mon Sep 17 00:00:00 2001 From: Debian Date: Sun, 24 May 2026 12:36:53 +0200 Subject: [PATCH] =?UTF-8?q?fix(haproxy+unbound):=20http=5Fto=5Fhttps=20per?= =?UTF-8?q?=20Domain=20+=20leere=20Forward-Zones=20=C3=BCberspringen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit haproxy: http_to_https=false Domains bekommen jetzt eigene use_backend-Regeln im public_http-Frontend statt dem globalen HTTPS-Redirect. Das Feld war bisher in DB + UI vorhanden aber vom Config-Generator komplett ignoriert. unbound: Forward-Zones ohne forward-addr (ForwardTo=nil oder leer) werden jetzt übersprungen. Unbound lehnt solche Blöcke beim Start ab. Co-Authored-By: Claude Sonnet 4.6 --- 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 | 19 +++++++++++++++---- internal/haproxy/haproxy.go | 12 +++++++++++- internal/unbound/unbound.go | 3 +++ 7 files changed, 33 insertions(+), 9 deletions(-) diff --git a/VERSION b/VERSION index 1674756..6daa822 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.81 +1.1.82 diff --git a/cmd/edgeguard-api/main.go b/cmd/edgeguard-api/main.go index e993711..e622712 100644 --- a/cmd/edgeguard-api/main.go +++ b/cmd/edgeguard-api/main.go @@ -60,7 +60,7 @@ import ( usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users" ) -var version = "1.1.81" +var version = "1.1.82" func main() { addr := os.Getenv("EDGEGUARD_API_ADDR") diff --git a/cmd/edgeguard-ctl/main.go b/cmd/edgeguard-ctl/main.go index 14d09f5..28c32e7 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.1.81" +var version = "1.1.82" const usage = `edgeguard-ctl — EdgeGuard CLI diff --git a/cmd/edgeguard-scheduler/main.go b/cmd/edgeguard-scheduler/main.go index e952b0a..2e25c96 100644 --- a/cmd/edgeguard-scheduler/main.go +++ b/cmd/edgeguard-scheduler/main.go @@ -35,7 +35,7 @@ import ( "git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts" ) -var version = "1.1.81" +var version = "1.1.82" const ( // renewTickInterval — how often we re-evaluate expiring certs. diff --git a/internal/haproxy/haproxy.cfg.tpl b/internal/haproxy/haproxy.cfg.tpl index f3fd3fd..ddd1799 100644 --- a/internal/haproxy/haproxy.cfg.tpl +++ b/internal/haproxy/haproxy.cfg.tpl @@ -32,7 +32,8 @@ defaults # ── Public :80 ───────────────────────────────────────────────────────── # ACME-01 challenges proxy to edgeguard-api which serves the webroot. -# Everything else redirects to HTTPS. +# Domains with http_to_https=false bypass the redirect and are proxied +# directly. Everything else redirects to HTTPS. frontend public_http bind :80 {{- if .IPv6Enabled}} @@ -40,11 +41,21 @@ frontend public_http {{- end}} acl is_acme path_beg /.well-known/acme-challenge/ + {{- range $d := .HTTPDomains}} + acl is_http_only hdr(host) -i {{$d.Name}} + {{- end}} - # Redirect to HTTPS first (skipped for ACME paths) — must come - # before use_backend so HAProxy doesn't warn about ordering. - http-request redirect scheme https code 301 unless is_acme + # Redirect to HTTPS (skipped for ACME and http-only domains). + http-request redirect scheme https code 301 unless is_acme{{if .HTTPDomains}} or is_http_only{{end}} + {{- range $d := .HTTPDomains}} + {{- range $r := $d.Routes}} + use_backend eg_backend_{{$r.BackendID}} if { hdr(host) -i {{$d.Name}} } { path_beg {{$r.PathPrefix}} } + {{- end}} + {{- if $d.PrimaryBackendID}} + use_backend eg_backend_{{$d.PrimaryBackendID}} if { hdr(host) -i {{$d.Name}} } + {{- end}} + {{- end}} use_backend api_backend if is_acme # ── Public :443 (Customer-Backends only) ────────────────────────────── diff --git a/internal/haproxy/haproxy.go b/internal/haproxy/haproxy.go index edbce50..9276357 100644 --- a/internal/haproxy/haproxy.go +++ b/internal/haproxy/haproxy.go @@ -133,6 +133,10 @@ type View struct { Domains []DomainView Backends []BackendView + // HTTPDomains: aktive Domains mit HTTPToHTTPS=false. Diese bekommen + // in public_http eigene use_backend-Regeln statt dem globalen Redirect. + HTTPDomains []DomainView + // GlobalMaintenance: wenn true emittiert public_https einen // 503-Block ganz am Anfang (vor allen anderen ACLs), der // alle Customer-Domains gleichzeitig stilllegt. mgmt_https @@ -278,7 +282,13 @@ func (g *Generator) loadView(ctx context.Context) (*View, error) { domViews = append(domViews, dv) } - v := &View{Domains: domViews, Backends: activeBackends} + httpDomains := make([]DomainView, 0) + for _, dv := range domViews { + if !dv.HTTPToHTTPS && (dv.PrimaryBackendID != nil || len(dv.Routes) > 0) { + httpDomains = append(httpDomains, dv) + } + } + v := &View{Domains: domViews, Backends: activeBackends, HTTPDomains: httpDomains} if g.SetupStore != nil { if st, err := g.SetupStore.Load(); err == nil && st != nil { v.GlobalMaintenance = st.MaintenanceMode diff --git a/internal/unbound/unbound.go b/internal/unbound/unbound.go index d9214e3..a2a6c41 100644 --- a/internal/unbound/unbound.go +++ b/internal/unbound/unbound.go @@ -136,6 +136,9 @@ func (g *Generator) buildView(ctx context.Context) (*View, error) { if z.ForwardTo != nil { fwd = splitCSV(*z.ForwardTo) } + if len(fwd) == 0 { + continue // skip — Unbound rejects a forward-zone without forward-addr + } view.ForwardZones = append(view.ForwardZones, forwardZoneView{ Name: z.Name, Forwarders: fwd, })