[os-nginx] Add hostnames; to SNI Upstream Maps and proxy_protocol on; to Stream Servers
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 1.2k
- Forks
- 863
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 10
Description
Important notices
Before you add a new report, we ask you kindly to acknowledge the following:
- I have read the contributing guide lines at https://github.com/opnsense/plugins/blob/master/CONTRIBUTING.md
- I have searched the existing issues, open and closed, and I'm convinced that mine is new.
- When the request is meant for an existing plugin, I've added its name to the title.
Is your feature request related to a problem? Please describe.
The current Stream/SNI configuration does not expose two Nginx options required for a specific SNI-based TLS pass-through use case.
-
First, SNI Upstream Maps cannot enable hostnames;, which prevents using Nginx's hostname matching syntax (for example, .example.com) to route a domain and all of its subdomains to the same upstream.
-
Second, Stream Servers cannot enable proxy_protocol on;. This is required when the upstream is selected dynamically through an SNI map, in order to preserve and forward the original client IP to the upstream.
These limitations prevent using the OPNsense Nginx plugin for a complete TLS pass-through configuration where routing is based on SNI and the upstream also needs the original client IP.
Describe the solution you'd like
I would like the following two options to be added to the Stream/SNI configuration:
Add an option to SNI Upstream Maps to enable Nginx's hostnames; directive inside the generated map {} block. This would allow hostname patterns such as .example.com to match both the domain and all of its subdomains.
Add a Proxy Protocol option to Stream Servers which generates proxy_protocol on; inside the corresponding server {} block. This is required when using a variable-based proxy_pass whose upstream is selected by an SNI map and you need to pass the real IP address to the upstream.
For example, the plugin should be able to generate a configuration equivalent to:
map $ssl_preread_server_name $upstream {
hostnames;
.example1.com netbird;
example2.com opnsense;
example3.com opnsense;
}
server {
listen 443;
ssl_preread on;
proxy_protocol on;
proxy_pass $upstream;
}
Describe alternatives you've considered
I considered using the existing configuration hooks provided by the plugin to add the missing directives manually.
The proxy_protocol on; directive can be added through an available Stream Server hook, and I was able to verify that this part of the configuration works as expected.
However, there is no corresponding hook inside the generated SNI Upstream Map, where the hostnames; directive needs to be placed. Therefore, in my tests I had to use a specific single domain.
Additional context
The feature request comes from the need to deploy a fully featured NetBird server, which requires its own reverse proxy, while preserving the existing HTTPS services exposed through Nginx on the same public IP and port.
The setup is:
- NetBird runs in Docker on the LAN and provides its own reverse proxy with PROXY PROTOCOL.
- OPNsense runs Nginx as the Internet-facing reverse proxy.
- Nginx must perform TLS pass-through and route connections based on the TLS SNI, without terminating TLS.
- The NetBird reverse proxy must receive the original client IP through the PROXY Protocol.
- A domain and all of its subdomains need to be routed to the NetBird upstream using Nginx hostname matching.
- The rest of the domains that are not intended to be forwarded to Netbird can be forwarded to the Nginx proxy to be handled as usual with TLS termination.
The intended architecture is essentially:
I was able to test the proxy_protocol on; part using the existing Stream Server hook and confirmed that this mechanism works.
I could not complete the test of the full configuration because the existing hooks do not provide a way to insert hostnames; inside the generated SNI Upstream Map.
The internal Nginx HTTP listener has to use a different port because the Stream Server needs to own TCP port 443 for SNI prereading. Since proxy_protocol on; is enabled at the Stream Server level, the HTTP servers receiving those internally forwarded connections also need to be configured to accept PROXY Protocol.
The requested changes would therefore allow this configuration to be fully managed and persisted through the OPNsense Nginx GUI instead of relying on custom configuration via hooks.
Why proxy_protocol on; is required in the server {} block
Nginx also provides proxy_protocol at the upstream server level. However, in this use case the upstream is selected dynamically through a map using $ssl_preread_server_name.
When proxy_pass uses the variable resulting from the map, the proxy_protocol setting configured on the individual upstream server cannot be used to enable PROXY Protocol for that dynamically selected upstream.
Therefore, proxy_protocol on; must be configured in the stream server {} block:
server {
listen 443;
ssl_preread on;
proxy_protocol on;
proxy_pass $upstream;
}
This necessarily applies PROXY Protocol to all upstreams selected by that server, which is acceptable for this use case because all relevant upstreams are expected to support PROXY Protocol.
The requirement is therefore specifically to expose the proxy_protocol on; option at the Stream Server level.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating the os-nginx code that generates SNI Upstream Maps and Stream Servers, then inspect the existing Stream Server hook and generated Nginx configuration. Add persisted GUI options that produce hostnames; inside the map block and proxy_protocol on; inside the server block, and verify the resulting configuration supports the documented TLS pass-through example.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- nginx, php
- Domain
- infrastructure, networking
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100