{"record":{"id":"eb2ac74a13d278a0","repo":"ory/hydra","slug":"expected-x-forwarded-proto-header-to-be-https-but","errorCode":null,"errorMessage":"expected X-Forwarded-Proto header to be https but got: %s","messagePattern":"expected X-Forwarded-Proto header to be https but got: (.+?)","errorType":"http","errorClass":null,"httpStatus":502,"severity":"error","filePath":"oryx/tlsx/termination.go","lineNumber":67,"sourceCode":"\t\t\td.Logger().WithRequest(r).WithError(errors.New(\"TLS termination is not enabled\")).Error(\"Could not serve http connection\")\n\t\t\td.Writer().WriteErrorCode(rw, r, http.StatusBadGateway, errors.New(\"can not serve request over insecure http\"))\n\t\t\treturn\n\t\t}\n\n\t\tif err := matchesRange(r, networks); err != nil {\n\t\t\td.Logger().WithRequest(r).WithError(err).Warnln(\"Could not serve http connection\")\n\t\t\td.Writer().WriteErrorCode(rw, r, http.StatusBadGateway, errors.New(\"can not serve request over insecure http\"))\n\t\t\treturn\n\t\t}\n\n\t\tproto := r.Header.Get(\"X-Forwarded-Proto\")\n\t\tif proto == \"\" {\n\t\t\td.Logger().WithRequest(r).WithError(errors.New(\"X-Forwarded-Proto header is missing\")).Error(\"Could not serve http connection\")\n\t\t\td.Writer().WriteErrorCode(rw, r, http.StatusBadGateway, errors.New(\"can not serve request over insecure http\"))\n\t\t\treturn\n\t\t} else if proto != \"https\" {\n\t\t\td.Logger().WithRequest(r).WithError(errors.New(\"X-Forwarded-Proto header is missing\")).Error(\"Could not serve http connection\")\n\t\t\td.Writer().WriteErrorCode(rw, r, http.StatusBadGateway, errors.Errorf(\"expected X-Forwarded-Proto header to be https but got: %s\", proto))\n\t\t\treturn\n\t\t}\n\n\t\tnext(rw, r)\n\t}), nil\n}\n\nfunc matchesRange(r *http.Request, networks []*net.IPNet) error {\n\tremoteIP, _, err := net.SplitHostPort(r.RemoteAddr)\n\tif err != nil {\n\t\treturn errors.WithStack(err)\n\t}\n\n\tcheck := []string{remoteIP}\n\tfor fwd := range strings.SplitSeq(r.Header.Get(\"X-Forwarded-For\"), \",\") {\n\t\tcheck = append(check, strings.TrimSpace(fwd))\n\t}\n","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/tlsx/termination.go#L49-L85","documentation":"This error is returned by the EnforceTLSRequests middleware in oryx/tlsx when a request arrives over plain HTTP (r.TLS == nil), the client IP is inside an allowed termination CIDR, but the X-Forwarded-Proto header is present yet not equal to \"https\". The middleware trusts a TLS-terminating proxy (load balancer, ingress, reverse proxy) to set this header correctly, and refuses to serve traffic whose forwarded protocol does not indicate HTTPS. It responds with HTTP 502 Bad Gateway and this message echoing the actual header value.","triggerScenarios":"A proxy/ingress terminates TLS but forwards X-Forwarded-Proto: http (or http/1.1, http, HTTP, etc.) to the Ory service; a misconfigured load balancer health/forwarding rule; a developer curling the internal plain-HTTP port while the ingress injects a wrong header value.","commonSituations":"Kubernetes ingress (nginx, ALB) with ssl-redirect or X-Forwarded-Proto override misconfigured; Cloudflare in Flexible SSL mode sending proto=http; double proxies where the inner proxy overwrites X-Forwarded-Proto; self-signed local TLS setups where the upstream port is accessed over http.","solutions":["Fix the TLS-terminating proxy to set X-Forwarded-Proto: https when the original request was HTTPS (e.g. nginx: proxy_set_header X-Forwarded-Proto $scheme; with the external listener on 443).","If using Cloudflare or an ALB, switch SSL mode from Flexible to Full/Full(strict) so the forwarded proto is https.","Ensure no intermediate proxy overwrites the header; remove duplicate proxy_set_header directives.","For local testing over plain HTTP, add the client IP to allowTerminationFrom and bypass the proxy, or serve the service directly over TLS."],"exampleFix":"// before (nginx location behind TLS)\nproxy_set_header X-Forwarded-Proto http;\n// after\nproxy_set_header X-Forwarded-Proto https;","handlingStrategy":"validation","validationCode":"// ensure your proxy sets the header before forwarding\nif r.Header.Get(\"X-Forwarded-Proto\") != \"https\" {\n    // request will be rejected by EnforceTLSRequests; fix proxy config first\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always configure X-Forwarded-Proto: https on TLS-terminating proxies (nginx/ALB/Cloudflare).","Use Cloudflare Full (strict) SSL, not Flexible mode.","Test the full proxy chain with curl -H 'X-Forwarded-Proto: http' to reproduce before deploy."],"tags":["http","tls","proxy","oryx"],"backgroundTag":"x-forwarded-proto-mismatch","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}