Fixing Server-Side Includes (SSI) in NGINX Gateway Fabric
These articles are AI-generated summaries. Please check the original sources for full details.
How I Fixed an SSI-Breaking Bug in NGINX Gateway Fabric
Michael Uanikehi discovered a critical bug in NGINX Gateway Fabric that caused Server-Side Includes (SSI) to fail during infrastructure migrations. The root cause was identified as the immutable nature of the $request_uri variable, which forced internal subrequests to hit incorrect backend paths.
Why This Matters
In the transition from NGINX Ingress Controller to the Kubernetes Gateway API-based NGINX Gateway Fabric, subtle differences in NGINX configuration generation can break legacy features. This case demonstrates that while ideal models abstract complexity, technical reality requires a deep understanding of NGINX variables like $request_uri, which remains constant even during internal subrequests, potentially causing silent failures in SSI or authentication subrequests.
Key Insights
- The $request_uri variable in NGINX is immutable across the entire request lifecycle, including internal subrequests (Uanikehi, 2026).
- NGINX Gateway Fabric utilizes NJS-driven HTTP matching which requires internal redirects using r.internalRedirect to process matching rules.
- External locations match client requests directly where $uri is already processed, making the use of $request_uri redundant and harmful for SSI.
- The bug fix required a conditional check in the createProxyPass function to differentiate between External and Internal location types.
- NGINX Gateway Fabric was verified using a local kind cluster to ensure proxy_pass directives no longer appended $request_uri for external locations.
Working Examples
A standard SSI pattern that triggers a subrequest for include.html.
<h1>SSI Test Page</h1>
<!--# include virtual="/include.html" -->
The logic change in internal/controller/nginx/config/servers.go ensuring $request_uri is only used for internal locations.
// Before fix
if !grpc {
if filter == nil || filter.Path == nil {
requestURI = "$request_uri"
}
}
// After fix
if !grpc && locationType == http.InternalLocationType {
if filter == nil || filter.Path == nil {
requestURI = "$request_uri"
}
}
Practical Applications
- Migration from NGINX Ingress Controller to Gateway Fabric: System administrators must verify that SSI-enabled services do not have $request_uri appended to proxy_pass, which would otherwise ignore subrequest paths.
- NJS-driven routing: Developers using NJS for complex matching must ensure that internal redirects correctly restore the client URI without breaking subrequest functionality in subsequent location blocks.
References:
Continue reading
Next article
Automating Google Colab with AI Agents: A Guide to colab-mcp and FastMCP
Related Content
Visualize BGP with Containerlab and FRRouting Dashboard
Build a live BGP topology dashboard using Containerlab and FRRouting, enabling a four-router lab to run on just 350 MB of RAM.
Optimizing Cloudflare Cache Rates: Fixing Astro SSR Headers with Nginx Map
Learn how an Nginx map directive increased Cloudflare cache rates from 1.1% to 47.3% by overriding Astro Node adapter defaults.
Building a Cloud VPC from Scratch Using Linux Tools
A hands-on guide to building a Linux-based VPC with ip, iptables, and network namespaces, replicating AWS functionality without cloud dependencies.