Important notices
Before you add a new report, we ask you kindly to acknowledge the following:
Is your feature request related to a problem? Please describe.
The www/nginx plugin currently hardcodes these upstream request headers in location.conf:
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Host ...;
Source:
|
proxy_set_header X-Real-IP $remote_addr; |
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
|
proxy_set_header X-Forwarded-Proto $scheme; |
|
proxy_set_header X-Forwarded-Port $server_port; |
|
proxy_set_header X-Forwarded-Host {% if upstream.x_forwarded_host_verbatim is defined and upstream.x_forwarded_host_verbatim == '1'%}$http_host{% else %}$host{% endif %}; |
There is no GUI option to change or disable X-Real-IP and X-Forwarded-For. There is also no configuration for RFC 7239 Forwarded.
The HTTP server configuration already supports real_ip_header and trusted proxy networks. This makes $remote_addr the validated client address after trusted-proxy processing.
However, $proxy_add_x_forwarded_for preserves a client-supplied X-Forwarded-For chain. This is valid for traditional proxy chains, but it does not allow OPNsense nginx to act as a strict client-IP trust boundary.
More importantly, incoming Forwarded headers are passed unchanged to the upstream because the template does not set or remove them. A backend which gives RFC 7239 Forwarded precedence can therefore accept a client-supplied spoofed address even though X-Real-IP was generated from $remote_addr.
Example topology:
Cloudflare (optional)
-> OPNsense nginx
-> application
With trusted Cloudflare networks and:
real_ip_header CF-Connecting-IP;
$remote_addr contains the validated Cloudflare client address. Without Cloudflare, an untrusted direct client cannot override $remote_addr, so it contains the TCP client address.
The existing include hooks cannot solve this safely:
http_post/*.conf cannot override the location-level proxy_set_header list because nginx inherits that list only when no directives exist at the lower level.
<location-uuid>_post/*.conf is included in the same location, but repeating a normal proxy_set_header name may generate duplicate header fields instead of replacing the generated definition.
Location post-hook:
|
include {{ location['@uuid'] }}_post/*.conf; |
Nginx documentation:
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header
Describe the solution you'd like
Please add first-class, location-scoped configuration for upstream client-address headers. The generated configuration must emit at most one effective proxy_set_header directive per header name.
Suggested X-Forwarded-For modes:
-
Append — current and backwards-compatible default:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-
Replace — use the validated client address:
proxy_set_header X-Forwarded-For $remote_addr;
-
Drop:
proxy_set_header X-Forwarded-For "";
Suggested Forwarded modes:
-
Preserve — current implicit behavior and backwards-compatible default.
-
Replace — generate a sanitized RFC 7239 value from the effective $remote_addr and request scheme.
-
Drop:
proxy_set_header Forwarded "";
RFC 7239 generation must correctly format IPv4 and IPv6 addresses. For example:
Forwarded: for=192.0.2.10;proto=https
Forwarded: for="[2001:db8::10]";proto=https
It should also be possible to suppress provider-specific client identity headers:
proxy_set_header CF-Connecting-IP "";
proxy_set_header True-Client-IP "";
An optional secure trust-boundary mode could generate:
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Forwarded "<RFC 7239 value generated from $remote_addr and $scheme>";
proxy_set_header CF-Connecting-IP "";
proxy_set_header True-Client-IP "";
Alternatively, the plugin could provide a name-based upstream request-header configuration where custom entries replace generated defaults by header name and an empty value suppresses the header.
The current behavior should remain the default for backwards compatibility.
Describe alternatives you've considered
- Patching
location.conf, which is overwritten by plugin/package upgrades.
- Using
<location-uuid>_post/*.conf, which can create duplicate headers.
- Using
http_post/*.conf, whose header directives are not inherited by generated proxy locations.
- Trusting only
X-Real-IP in the application, which does not sanitize Forwarded.
- Cloudflare Transform Rules, which do not work when Cloudflare is disabled.
- Reimplementing trusted proxy-chain handling independently in every backend.
Additional context
Related issues and discussions:
This request specifically concerns safe and deterministic handling of generated client-address headers. It is narrower than general arbitrary request-header support.
Important notices
Before you add a new report, we ask you kindly to acknowledge the following:
Is your feature request related to a problem? Please describe.
The
www/nginxplugin currently hardcodes these upstream request headers inlocation.conf:Source:
plugins/www/nginx/src/opnsense/service/templates/OPNsense/Nginx/location.conf
Lines 178 to 182 in 26f4c37
There is no GUI option to change or disable
X-Real-IPandX-Forwarded-For. There is also no configuration for RFC 7239Forwarded.The HTTP server configuration already supports
real_ip_headerand trusted proxy networks. This makes$remote_addrthe validated client address after trusted-proxy processing.However,
$proxy_add_x_forwarded_forpreserves a client-suppliedX-Forwarded-Forchain. This is valid for traditional proxy chains, but it does not allow OPNsense nginx to act as a strict client-IP trust boundary.More importantly, incoming
Forwardedheaders are passed unchanged to the upstream because the template does not set or remove them. A backend which gives RFC 7239Forwardedprecedence can therefore accept a client-supplied spoofed address even thoughX-Real-IPwas generated from$remote_addr.Example topology:
With trusted Cloudflare networks and:
$remote_addrcontains the validated Cloudflare client address. Without Cloudflare, an untrusted direct client cannot override$remote_addr, so it contains the TCP client address.The existing include hooks cannot solve this safely:
http_post/*.confcannot override the location-levelproxy_set_headerlist because nginx inherits that list only when no directives exist at the lower level.<location-uuid>_post/*.confis included in the same location, but repeating a normalproxy_set_headername may generate duplicate header fields instead of replacing the generated definition.Location post-hook:
plugins/www/nginx/src/opnsense/service/templates/OPNsense/Nginx/location.conf
Line 238 in 26f4c37
Nginx documentation:
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header
Describe the solution you'd like
Please add first-class, location-scoped configuration for upstream client-address headers. The generated configuration must emit at most one effective
proxy_set_headerdirective per header name.Suggested
X-Forwarded-Formodes:Append— current and backwards-compatible default:Replace— use the validated client address:Drop:Suggested
Forwardedmodes:Preserve— current implicit behavior and backwards-compatible default.Replace— generate a sanitized RFC 7239 value from the effective$remote_addrand request scheme.Drop:RFC 7239 generation must correctly format IPv4 and IPv6 addresses. For example:
It should also be possible to suppress provider-specific client identity headers:
An optional secure trust-boundary mode could generate:
Alternatively, the plugin could provide a name-based upstream request-header configuration where custom entries replace generated defaults by header name and an empty value suppresses the header.
The current behavior should remain the default for backwards compatibility.
Describe alternatives you've considered
location.conf, which is overwritten by plugin/package upgrades.<location-uuid>_post/*.conf, which can create duplicate headers.http_post/*.conf, whose header directives are not inherited by generated proxy locations.X-Real-IPin the application, which does not sanitizeForwarded.Additional context
Related issues and discussions:
This request specifically concerns safe and deterministic handling of generated client-address headers. It is narrower than general arbitrary request-header support.