ory/hydra · error
neither remote address nor any x-forwarded-for values match
Error message
neither remote address nor any x-forwarded-for values match CIDR ranges %+v: %v, ranges, check)
What it means
matchesRange verifies that a plain-HTTP request may be TLS-terminated by checking that either the direct RemoteAddr or any X-Forwarded-For entry falls inside one of the configured allowTerminationFrom CIDR ranges. If none of the candidate IPs (remote IP plus every comma-separated X-Forwarded-For value) is contained in any configured network, it returns this error and the middleware rejects the request with 502 Bad Gateway. It is the library's safeguard against accepting TLS-terminated traffic from untrusted proxies.
Source
Thrown at oryx/tlsx/termination.go:94
remoteIP, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
return errors.WithStack(err)
}
check := []string{remoteIP}
for fwd := range strings.SplitSeq(r.Header.Get("X-Forwarded-For"), ",") {
check = append(check, strings.TrimSpace(fwd))
}
for _, ipNet := range networks {
for _, ip := range check {
addr := net.ParseIP(ip)
if ipNet.Contains(addr) {
return nil
}
}
}
return errors.Errorf("neither remote address nor any x-forwarded-for values match CIDR ranges %+v: %v, ranges, check)", networks, check)
}
View on GitHub (pinned to 4174065ffb)
Solutions
- Add the actual proxy/source IP range to the allowTerminationFrom configuration (e.g. the Kubernetes node/pod CIDR or LB egress range).
- Verify with logs what RemoteAddr and X-Forwarded-For the service sees and confirm the CIDR notation is correct (net.ParseCIDR format, e.g. 10.0.0.0/8).
- If the proxy legitimately strips X-Forwarded-For, whitelist the proxy's direct IP instead.
- If you do not run a TLS-terminating proxy at all, serve the service over HTTPS directly so the middleware is bypassed (r.TLS != nil).
Example fix
// before (config) allowTerminationFrom: - 127.0.0.1/32 // after (include proxy subnet) allowTerminationFrom: - 127.0.0.1/32 - 10.244.0.0/16
Defensive patterns
Strategy: validation
Validate before calling
// verify source IP is inside allowTerminationFrom before deploying
ip := net.ParseIP(proxyIP)
_, cidr, _ := net.ParseCIDR("10.244.0.0/16")
if !cidr.Contains(ip) {
log.Printf("proxy IP %s not in allowTerminationFrom", proxyIP)
} Prevention
- Whitelist whole subnets (pod/node CIDR), not single IPs, in allowTerminationFrom.
- Re-check the config whenever proxy infrastructure changes (new LB, node pool resize).
- Log RemoteAddr and X-Forwarded-For on 502 responses to debug range mismatches quickly.
When it happens
Trigger: A request arrives over plain HTTP, allowTerminationFrom is configured, but the proxy's IP (RemoteAddr) and all X-Forwarded-For entries are outside the configured CIDR ranges — e.g. a new proxy pod IP, an SNAT-ed address, or the X-Forwarded-For header being stripped or appended with unexpected values.
Common situations: Kubernetes: proxy/ingress pods rescheduled onto nodes with IPs outside the configured subnet; adding a second load balancer whose egress IP is not whitelisted; configuring 127.0.0.1/32 but connecting through Docker bridge or a container network; X-Forwarded-For missing so only RemoteAddr is checked.
Related errors
- expected X-Forwarded-Proto header to be https but got: %s
- DNS lookup timed out
- no route to host
- can not serve request over insecure http
- could not start debug server on port %d: %w
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/6fb2cf423beb74b1.
Report an issue: GitHub.