From 7d5e4f4e29f329d1e1ebde5c43869762cff0e0ca Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Thu, 9 Jul 2026 14:15:32 +0000 Subject: [PATCH] fix: Skip L7 routes and central TLS in HAProxy when certs don't exist HAProxy validation fails if the config references cert files that don't exist (wildcard.pem for L7 routes, domain.pem for central TLS). Now reconciliation checks for cert existence before including: - L7 HTTP routes: only generated when wildcard cert exists - Central domain TLS frontend: only generated when domain cert exists This ensures HAProxy never enters a failure state due to missing certs. Once certs are provisioned (via certbot), the next reconciliation picks them up automatically. Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/api/v1/helpers.go | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/internal/api/v1/helpers.go b/internal/api/v1/helpers.go index a680dbf..94338cd 100644 --- a/internal/api/v1/helpers.go +++ b/internal/api/v1/helpers.go @@ -60,16 +60,41 @@ func (api *API) reconcileNetworking() { } } - // Determine central domain for HAProxy + // Determine central domain for HAProxy — only if its cert exists centralDomain := "" - if globalCfg.Cloud.Central.Domain != "" { - centralDomain = globalCfg.Cloud.Central.Domain + if d := globalCfg.Cloud.Central.Domain; d != "" { + if _, err := os.Stat(certbot.HAProxyCertPath(d)); err == nil { + centralDomain = d + } else { + slog.Debug("reconcile: skipping central domain in HAProxy (no cert)", "domain", d) + } + } + + // Only include L7 HTTP routes if a wildcard cert exists for TLS termination. + // Without it, HAProxy validation fails and the entire config is rejected. + wildcardCert := "/etc/haproxy/certs/wildcard.pem" + gatewayDomain := "" + if parts := strings.SplitN(globalCfg.Cloud.Central.Domain, ".", 2); len(parts) == 2 { + gatewayDomain = parts[1] + // Also check per-domain cert path + if _, err := os.Stat(certbot.HAProxyCertPath(gatewayDomain)); err == nil { + wildcardCert = certbot.HAProxyCertPath(gatewayDomain) + } + } + + activeHTTPRoutes := httpRoutes + if _, err := os.Stat(wildcardCert); err != nil { + if len(httpRoutes) > 0 { + slog.Warn("reconcile: skipping L7 HTTP routes in HAProxy (no wildcard cert)", "path", wildcardCert) + } + activeHTTPRoutes = nil } // Generate and write HAProxy config haproxyCfg := api.haproxy.GenerateWithOpts(instanceRoutes, nil, haproxy.GenerateOpts{ CentralDomain: centralDomain, - HTTPRoutes: httpRoutes, + HTTPRoutes: activeHTTPRoutes, + WildcardCert: wildcardCert, }) if err := api.haproxy.WriteConfig(haproxyCfg); err != nil {