mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2026-04-26 09:55:51 +03:00
[GH-ISSUE #853] SSL Passthrough #723
Labels
No labels
awaiting feedback
bug
cannot reproduce
dns provider request
duplicate
enhancement
enhancement
enhancement
good first issue
help wanted
invalid
need more info
no certbot plugin available
product-support
pull-request
question
stale
troll
upstream issue
v2
v2
v2
v3
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/nginx-proxy-manager-NginxProxyManager#723
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @ctops1 on GitHub (Jan 31, 2021).
Original GitHub issue: https://github.com/NginxProxyManager/nginx-proxy-manager/issues/853
Is your feature request related to a problem? Please describe.
Unable to pass through encrypted SSL connections to a server that doesn't need SSL encryption
Describe the solution you'd like
A clear option or configuration to enable SSL passthrough via stream or similar method.
Describe alternatives you've considered
Attempted to add code from links under additional context, host simply goes offline.
Additional context
This has been discussed in some other unclosed issues linked at the bottom, but this should be possible with modern NGINX using the stream function. I see that NPM has "Stream" but it only allows you to capture an entire port instead of a specified domain for forwarding to another internal host.
https://serversforhackers.com/c/tcp-load-balancing-with-nginx-ssl-pass-thru
https://stackoverflow.com/questions/38371840/ssl-pass-through-in-nginx-reverse-proxy
https://github.com/jc21/nginx-proxy-manager/issues/235
https://github.com/jc21/nginx-proxy-manager/issues/461
@ma-karai commented on GitHub (Feb 23, 2021):
I have to say this would be a big feature. This would make dealing with cooler larger projects a breeze. Matrix/synapse comes to mind which is a pain to setup behind a separate proxy. It would be nice if you could just forward a specific domain 80 and 443 traffic to a service on a separate machine that does the ssl stuff.
@ctops1 commented on GitHub (Feb 25, 2021):
After spending a lot of time getting this to work in NGINX itself - I realize this request may not fulfill everyone's needs even if it was implemented according to what NGINX supports.
NGINX can do SSL passthru, but it can't do it on the same ports being serviced for normal NGINX services. You can do only one or the other.
For example, let's say you have some sites on 443 using normal NGINX SSL. You cannot then also use NGINX to perform passthrough to a VM that has its own certificates. You would have to use a different port, such as 8443 or a custom port. The only other alternative would be another box and another public IP.
I finally resolved my issue by switching back to pure NGINX and implementing passthru on 8443 and the rest of our sites on 443.
NPM is a great tool but it has its limitations - perhaps someday I will revisit it and I will still recommend it to those who have less complex setups than I.
@centralhardware commented on GitHub (Mar 11, 2021):
for ssl pasthrough you need to use stream (npm now support it), but i think you can't use stream and http on the same port.
@chaptergy commented on GitHub (Oct 12, 2021):
SSL passthrough in nginx is complicated. So the only way to have ssl passthrough is by using a stream host. But in a stream host nginx has no idea what protocol is used by the data. Nginx can assume it is HTTP, but since it is HTTPS the data is encrypted, so even if nginx knows it is HTTP, he still does not now where to send this packet, as the target domain is encrypted as well. But there is a relatively new feature in nginx, which leverages Server Name Indication in TLS, where the domain is sent unencrypted in the HTTPS request. But this means the requesting client also has to send this SNI. But most modern browsers do, so let's just assume it is sent.
Here's the next problem: nginx cant run a stream on the same port as other proxies. It's one stream per port, and a port with a stream attached can't have any other proxies attached. We can work around this by routing all HTTPS traffic through this single stream, which in turn forwards it either to the ssl passthrough server or back to nginx itself on a different port, which can now handle all normal proxies. As you can imagine this will come with a performance penalty of all other proxies being proxied twice, and it might become a bottleneck.
That's why I have implemented it in this specific way: SSL Passthough is a new type of host which is strictly opt-in. Once you have opted in, all traffic is routed through the single stream as described above, but you will be able to add ssl passthrough hosts for a specific domain.
Remeber: Enabling SSL passthrough might slow down other proxied services and might break access for devices / browsers which do not send the SNI information!
@gabuzi commented on GitHub (May 28, 2023):
I was looking for this feature as well. Since the above PR #1479 doesn't seem to have been merged, I baked my own quick fix. It's not pretty but seems to do the trick (not tested thoroughly yet). Sharing here as it might help others.
Note that this approach makes designates an new port as the main input port for your NPM https traffic! This worked for me because I am behind NAT and could simply adjust the port forwarding for the public 443 port to a new port, and leave all the remaining NPM configuratio untouched. You might have to find another way if your NPM is directly listening on a public IP.
This also comes with the caveats mentioned by @chaptergy regarding dual-proxying.
So here goes:
Add the following to your custom
stream.conf(see https://nginxproxymanager.com/advanced-config/#custom-nginx-configurations) to passthrough SSL traffic for backend.example.com to the host 192.168.0.1:443 and backend2.example.com to 192.168.0.3:443:This is more or less a straight copy from the nginx docs example (https://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html) with the addition of the npm -> localhost:443 default backend.
Just add additional hostnames to the mapping and backends as required.
You might still need http proxy hosts on port 80 to make letsencrypt challenges work to those passed-through hosts.
Related issues: #776 #286
@github-actions[bot] commented on GitHub (Mar 20, 2024):
Issue is now considered stale. If you want to keep it open, please comment 👍
@jdkruzr commented on GitHub (Mar 22, 2024):
Does this work for anyone else? I made these changes, got rid of backend2 (I only have one host I need to do SNI passthrough for) but all it did was break all my existing hosts and it never started listening on 12346.
@gabuzi commented on GitHub (Mar 31, 2024):
Still working for me with 2.11.1.
But I noticed a rather severe caveat for security: This extra layer of proxying breaks access list functionality as for the npm backend now all requests appear to come from the localhost, such that IP filtering is not possible!
nginx proxy protocol would help here to retain the original IP, but it's not available for npm, see https://github.com/NginxProxyManager/nginx-proxy-manager/issues/1114
@github-actions[bot] commented on GitHub (Dec 15, 2024):
Issue is now considered stale. If you want to keep it open, please comment 👍
@bigdocloud commented on GitHub (Jan 2, 2025):
Hi @gabuzi, thanks for sharing the solution. But I couldn't get this solution working for me. Like many others, I need to pass 443 to a VM which expects its own SSL service for a domain, NPM takes SSL service for other domains.
With your solution, I add the script to stream.conf in Custom folder and update it with my own information accordingly. I can confirm the stream.conf has been read by nginx, but it doesn't pass 443. I mean if I request HTTPS to the domain, it responds "can't reach this page". HTTP works well to this domain which I pass HTTP with normal NPM forwarding configuration.
Did I miss any configuration requirement in addition to the "stream.conf" file? What is the "12346" port? As per your note - "Note that this approach makes designates an new port as the main input port for your NPM https traffic!", is this the port 12346 you referred to? Do I need to open this port or forward it from the firewall? or any recommended configuration? Thanks in advance.
@github-actions[bot] commented on GitHub (Nov 11, 2025):
Issue is now considered stale. If you want to keep it open, please comment 👍