diff --git a/openflare_server/router/api_phase2_test.go b/openflare_server/router/api_phase2_test.go index 352e6ed3..278b8f88 100644 --- a/openflare_server/router/api_phase2_test.go +++ b/openflare_server/router/api_phase2_test.go @@ -427,6 +427,12 @@ func TestPhase2CustomHeadersPreviewAndDiffLifecycle(t *testing.T) { if !strings.Contains(renderedConfig, `proxy_set_header Host "preview-upstream.internal";`) { t.Fatalf("expected preview endpoint to return overridden host header, got %s", renderedConfig) } + if !strings.Contains(renderedConfig, "proxy_ssl_server_name on;") { + t.Fatalf("expected preview endpoint to enable proxy ssl server name, got %s", renderedConfig) + } + if !strings.Contains(renderedConfig, `proxy_ssl_name "preview-upstream.internal";`) { + t.Fatalf("expected preview endpoint to return proxy ssl name, got %s", renderedConfig) + } diffResp := performJSONRequest(t, engine, token, http.MethodGet, "/api/config-versions/diff", nil) var diff map[string]any diff --git a/openflare_server/service/config_version.go b/openflare_server/service/config_version.go index 75a68729..e917a992 100644 --- a/openflare_server/service/config_version.go +++ b/openflare_server/service/config_version.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "net/url" "openflare/common" "openflare/model" "sort" @@ -749,7 +750,7 @@ func nextVersionNumber(now time.Time) (string, error) { } func renderHTTPProxyServer(domain string, originURL string, originHost string, customHeaders []ProxyRouteCustomHeaderInput) string { - return fmt.Sprintf("server {\n listen 80;\n server_name %s;\n%s\n location / {\n%s proxy_pass %s;\n }\n}\n\n", domain, renderExactHostGuard(domain), renderProxyHeaderBlock(originHost, customHeaders), originURL) + return fmt.Sprintf("server {\n listen 80;\n server_name %s;\n%s\n location / {\n%s proxy_pass %s;\n }\n}\n\n", domain, renderExactHostGuard(domain), renderProxyHeaderBlock(originURL, originHost, customHeaders), originURL) } func renderHTTPRedirectServer(domain string) string { @@ -759,20 +760,24 @@ func renderHTTPRedirectServer(domain string) string { func renderHTTPSServer(domain string, originURL string, originHost string, certificateID uint, customHeaders []ProxyRouteCustomHeaderInput) string { certPath := fmt.Sprintf("%s/%s", nginxCertDirPlaceholder, certificateCertFileName(certificateID)) keyPath := fmt.Sprintf("%s/%s", nginxCertDirPlaceholder, certificateKeyFileName(certificateID)) - return fmt.Sprintf("server {\n listen 443 ssl;\n server_name %s;\n ssl_certificate %s;\n ssl_certificate_key %s;\n%s\n location / {\n%s proxy_pass %s;\n }\n}\n\n", domain, certPath, keyPath, renderExactHostGuard(domain), renderProxyHeaderBlock(originHost, customHeaders), originURL) + return fmt.Sprintf("server {\n listen 443 ssl;\n server_name %s;\n ssl_certificate %s;\n ssl_certificate_key %s;\n%s\n location / {\n%s proxy_pass %s;\n }\n}\n\n", domain, certPath, keyPath, renderExactHostGuard(domain), renderProxyHeaderBlock(originURL, originHost, customHeaders), originURL) } func renderExactHostGuard(domain string) string { return fmt.Sprintf(" if ($host != %q) {\n return 404;\n }\n", domain) } -func renderProxyHeaderBlock(originHost string, customHeaders []ProxyRouteCustomHeaderInput) string { +func renderProxyHeaderBlock(originURL string, originHost string, customHeaders []ProxyRouteCustomHeaderInput) string { var builder strings.Builder if strings.TrimSpace(originHost) != "" { builder.WriteString(fmt.Sprintf(" proxy_set_header Host %s;\n", quoteNginxHeaderValue(originHost))) } else { builder.WriteString(" proxy_set_header Host $host;\n") } + if upstreamServerName := resolveUpstreamServerName(originURL, originHost); upstreamServerName != "" { + builder.WriteString(" proxy_ssl_server_name on;\n") + builder.WriteString(fmt.Sprintf(" proxy_ssl_name %s;\n", quoteNginxHeaderValue(upstreamServerName))) + } builder.WriteString(" proxy_set_header X-Real-IP $remote_addr;\n") builder.WriteString(" proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n") builder.WriteString(" proxy_set_header X-Forwarded-Proto $scheme;\n") @@ -790,6 +795,21 @@ func renderProxyHeaderBlock(originHost string, customHeaders []ProxyRouteCustomH return builder.String() } +func resolveUpstreamServerName(originURL string, originHost string) string { + parsed, err := url.Parse(originURL) + if err != nil || !strings.EqualFold(parsed.Scheme, "https") { + return "" + } + if strings.TrimSpace(originHost) != "" { + parsedHost, err := url.Parse("//" + originHost) + if err == nil && parsedHost.Hostname() != "" { + return parsedHost.Hostname() + } + return originHost + } + return parsed.Hostname() +} + func quoteNginxHeaderValue(value string) string { escaped := strings.ReplaceAll(value, `\`, `\\`) escaped = strings.ReplaceAll(escaped, `"`, `\"`) diff --git a/openflare_server/service/https_phase1_test.go b/openflare_server/service/https_phase1_test.go index da82edb4..6e4f9528 100644 --- a/openflare_server/service/https_phase1_test.go +++ b/openflare_server/service/https_phase1_test.go @@ -160,6 +160,12 @@ func TestPublishConfigVersionOverridesOriginHostHeader(t *testing.T) { if !strings.Contains(result.Version.RenderedConfig, `proxy_set_header Host "git.arctel.net";`) { t.Fatal("expected rendered config to override host header for origin routing") } + if !strings.Contains(result.Version.RenderedConfig, "proxy_ssl_server_name on;") { + t.Fatal("expected rendered config to enable proxy ssl server name for https origin") + } + if !strings.Contains(result.Version.RenderedConfig, `proxy_ssl_name "git.arctel.net";`) { + t.Fatal("expected rendered config to set proxy ssl name from origin host override") + } if !strings.Contains(result.Version.SnapshotJSON, `"origin_host":"git.arctel.net"`) { t.Fatal("expected snapshot to include origin_host override") }