Add SSL to streams
Support for SSL for streams with TCP forwarding enabled. Uses the same web interface as creating a new Proxy Host for adding SSL.
Details
An Nginx stream config created with this SSL feature looks like this:
# ------------------------------------------------------------
# 1883 TCP: 1 UDP: 1
# ------------------------------------------------------------
server {
listen 1883 ssl;
listen [::]:1883 ssl;
# Let's Encrypt SSL
include conf.d/include/ssl-cache-stream.conf;
include conf.d/include/ssl-ciphers.conf;
ssl_certificate /etc/letsencrypt/live/npm-9/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/npm-9/privkey.pem;
proxy_pass google.com:443;
# Custom
include /data/nginx/custom/server_stream[.]conf;
include /data/nginx/custom/server_stream_tcp[.]conf;
}
server {
listen 1883 udp;
listen [::]:1883 udp;
proxy_pass google.com:443;
# Custom
include /data/nginx/custom/server_stream[.]conf;
include /data/nginx/custom/server_stream_udp[.]conf;
}
Nginx doesn't allow stream and http blocks to share an SSL cache, so all streams have a separate SSL cache defined in ssl-cache-stream.conf:
ssl_session_cache shared:SSL_stream:50m;
Use a DNS Challenge is forced as streams cannot perform HTTP authentication for issuing certificates.
Streams do not have domain names associated with them in the database or displayed in the UI, as streams are not proxied by hostname but exclusively by port.
Related: #3368 #2542 #1829 #795
@jbowring Do you have plans to update this PR with future releases?
@RobertPosluszny thanks for testing this PR and your feedback. I think I've found the issue you described and fixed it, please check and let me know!
I'll do some more testing myself and then update this PR with a pull from the develop branch.
@jc21 what else needs to be done before this PR can be merged? Thanks.
@jbowring looks like the issue of editing stream settings after creation was resolved! Thanks!
When testing the linked CI image the following error is shown in the browser console when trying to create a stream
TypeError: e[t] is undefined
r https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:1
190 https://MY-DOMAIN/js/14.bundle.14.js?v=2.11.3:1
190 https://MY-DOMAIN/js/14.bundle.14.js?v=2.11.3:1
r https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:1
showNginxStreamForm https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
promise callback*showNginxStreamForm https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
action https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
click ui.action@https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
dispatch https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
handle https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
add https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
xe https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
each https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:16
each https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:16
xe https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
on https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegate https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegateEvents https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegateEvents https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
setElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
setElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
_ensureElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
View https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
constructor https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
i https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showEmpty https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
onRender https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
promise callback*onRender https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
O https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
render https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
ae https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
show https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showChildView https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showAppContent https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:310
showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
promise callback*showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
Ze https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
i https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
s https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
[main.bundle.js:1:1930](https://MY-DOMAIN/js/main.bundle.js?v=2.11.3)
oe https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:1
(Async: promise callback)
showNginxStreamForm https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
action https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
click @ui.action https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
dispatch https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
handle https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
(Async: EventListener.handleEvent)
add https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
xe https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
each https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:16
each https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:16
xe https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
on https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegate https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegateEvents https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegateEvents https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
setElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
setElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
_ensureElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
View https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
constructor https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
i https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showEmpty https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
onRender https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
(Async: promise callback)
onRender https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
O https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
render https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
ae https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
show https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showChildView https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showAppContent https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:310
showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
(Async: promise callback)
showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
Ze https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
i https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
s https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
Uncaught (in promise) TypeError: e[t] is undefined
r https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:1
190 https://MY-DOMAIN/js/14.bundle.14.js?v=2.11.3:1
190 https://MY-DOMAIN/js/14.bundle.14.js?v=2.11.3:1
r https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:1
showNginxStreamForm https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
promise callback*showNginxStreamForm https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
action https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
click ui.action@https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
dispatch https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
handle https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
add https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
xe https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
each https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:16
each https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:16
xe https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
on https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegate https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegateEvents https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegateEvents https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
setElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
setElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
_ensureElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
View https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
constructor https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
i https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showEmpty https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
onRender https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
promise callback*onRender https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
O https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
render https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
ae https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
show https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showChildView https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showAppContent https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:310
showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
promise callback*showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
Ze https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
i https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
s https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
[main.bundle.js:1:356](https://MY-DOMAIN/js/main.bundle.js?v=2.11.3)
oe https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:1
(Async: promise callback)
showNginxStreamForm https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
action https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
click @ui.action https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
dispatch https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
handle https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
(Async: EventListener.handleEvent)
add https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
xe https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
each https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:16
each https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:16
xe https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
on https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegate https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegateEvents https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
delegateEvents https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
setElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
setElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
_ensureElement https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
View https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
constructor https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
i https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showEmpty https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
onRender https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
(Async: promise callback)
onRender https://MY-DOMAIN/js/9.bundle.9.js?v=2.11.3:1
O https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
render https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
ae https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
show https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showChildView https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showAppContent https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:310
showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
(Async: promise callback)
showNginxStream https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:27
Ze https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
i https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
s https://MY-DOMAIN/js/main.bundle.js?v=2.11.3:3
@jbowring any way to update this PR to keep in line with the latest updates? Is there a way I can help keep that in line until this PR gets merged into develop or latest?
This would be such a useful feature for anyone trying to secure their MQTT servers to the outside world, thanks for doing it, would be amazing to see this eventually merged to main.
@RobertPosluszny sorry I've been unable to maintain this for a while. I've added you as a collaborator to my repository; feel free to keep it up to date and update this pull request.
Hello, like a lot of people I'd really like to get SSL for MQTT working within NPM.
The dock image mentioned above at jc21/nginx-proxy-manager:github-pr-3789, it no longer there. I a way I can get this docker image?
Thanks in advance!
The image built above (build 7) doesn’t actually work, there’s an issue with the schema somewhere. I’ll update it when I’ve fixed the problem. Please don’t use it in the meantime.
@jbowring - thanks for your effort on integrating SSL for streams, its really appreciated. This will be a great feature for NPM. Given the number of open pull requests, looks like being the NPM maintainer might be a full time job!
I am new in Nginx stream. I want get something like that: connect to sstp.example.com:443 and stream to the 192.168.0.60:443; connect to www.example.com:443 and proxy to the 192.168.0.50:443; Will it work?
I am new in Nginx stream. I want get something like that: connect to sstp.example.com:443 and stream to the 192.168.0.60:443; connect to www.example.com:443 and proxy to the 192.168.0.50:443; Will it work?
I use this for securing MQTT streams, along side a bunch of other web services, but I believe, what your asking for will work. The sstp. sub-domain can proxy to something different than www.
I really wish the excellent addition would be merged into the main branch!
I use this for securing MQTT streams, along side a bunch of other web services, but I believe, what your asking for will work. The sstp. sub-domain can proxy to something different than www.
I really wish the excellent addition would be merged into the main branch!
What would the configuration look like? Do I need to set up a 'Proxy Hosts' to localhost and then reroute with 'Streams'? Like that?
Will this be merged?
Will this be merged?
Let's hope so. Looks like a perfect addition to current NPM functionality. Unfortunately, I'm not sure how we persuade the NPM maintainer to add this PR over any others.
Docker Image for build 13 is available on DockerHub as
nginxproxymanager/nginx-proxy-manager-dev:pr-3789Note: ensure you backup your NPM instance before testing this image! Especially if there are database changes Note: this is a different docker image namespace than the official image
I get the error SQLITE_ERROR: no such column: domain_names, I thought the schema is fixed in this version?
Will this be merged?
Unfortunately, I'm not sure how we persuade the NPM maintainer to add this PR over any others.
Buy some coffee for the maintainer (see github homepage) and mention this feature. No guarantees but a little extra caffeine can't hurt, no?
Docker Image for build 14 is available on
DockerHub
as nginxproxymanager/nginx-proxy-manager-dev:pr-3789
Note: ensure you backup your NPM instance before testing this image! Especially if there are database changes Note: this is a different docker image namespace than the official image
I've rebased this PR with latest changes and pushed to the stream-ssl branch.
You may test with this docker image:
nginxproxymanager/nginx-proxy-manager-dev:stream-ssl
but beware, this contains a database migration and you won't be able to go back to the latest code very easily, so you really should back up your database, data and letsencrypt folders before using this image.
I would like to write an integration test for this before merging but I can't seem to think of a simple use case. I may just have to use openssl to test the ciphers but it won't be a full end to end test.
I've rebased this PR with latest changes and pushed to the stream-ssl branch.
You may test with this docker image:
nginxproxymanager/nginx-proxy-manager-dev:stream-sslbut beware, this contains a database migration and you won't be able to go back to the
latestcode very easily, so you really should back up your database, data and letsencrypt folders before using this image.I would like to write an integration test for this before merging but I can't seem to think of a simple use case. I may just have to use openssl to test the ciphers but it won't be a full end to end test.
That's awesome news, I will update and test. Thank you very much!
Closing this PR and about to merge #4344
Thanks for merging this @jc21 and thank you for your efforts in maintaining NPM!