[GH-ISSUE #344] SSH and HTTPS Support? #303

Open
opened 2026-02-26 06:32:09 +03:00 by kerem · 32 comments
Owner

Originally created by @FantaBlueMystery on GitHub (Mar 30, 2020).
Original GitHub issue: https://github.com/NginxProxyManager/nginx-proxy-manager/issues/344

Can you add SSH Support? (Nice to have)

For example by my SSH-Proxy

stream {

    upstream ssh {
        server 10.8.0.16:22;
    }

    upstream https {
        server 10.8.0.15:443;
    }

    upstream https2 {
        server 10.8.0.18:443;
    }

    map $ssl_preread_server_name $name {
     mysdomain.com https2;
      default https;
    }

    map $ssl_preread_protocol $upstream {
        default ssh;
        "TLSv1.2" $name;
        "TLSv1.3" $name;
        "TLSv1.1" $name;
        "TLSv1.0" $name;
    }

    # SSH and SSL on the same port
    server {
        listen 443;

        proxy_pass $upstream;
        ssl_preread on;
    }
Originally created by @FantaBlueMystery on GitHub (Mar 30, 2020). Original GitHub issue: https://github.com/NginxProxyManager/nginx-proxy-manager/issues/344 Can you add SSH Support? (Nice to have) For example by my SSH-Proxy ``` stream { upstream ssh { server 10.8.0.16:22; } upstream https { server 10.8.0.15:443; } upstream https2 { server 10.8.0.18:443; } map $ssl_preread_server_name $name { mysdomain.com https2; default https; } map $ssl_preread_protocol $upstream { default ssh; "TLSv1.2" $name; "TLSv1.3" $name; "TLSv1.1" $name; "TLSv1.0" $name; } # SSH and SSL on the same port server { listen 443; proxy_pass $upstream; ssl_preread on; } ```
Author
Owner

@Thijmen commented on GitHub (Apr 11, 2020):

I am already forwarding SSH with streams, would this help you?

<!-- gh-comment-id:612498855 --> @Thijmen commented on GitHub (Apr 11, 2020): I am already forwarding SSH with streams, would this help you?
Author
Owner

@FantaBlueMystery commented on GitHub (Apr 14, 2020):

Hi there
Thanks for the answer! Your answer would only be a part
because according to the protocol "$ ssl_preread_protocol" it would have to be divided into "TLSv1.2", "TLSv1.3", "TLSv1.1", "TLSv1.0" and the "default" for the ssh.
All this would be necessary to separate the HTTPS and SSH on one port (443). If it could then be separated by domain, that would be wonderful.

Would that be possible with the streams in the UI? Can you set the stream again on port 443? It would be important that only one port is present on the outside.

<!-- gh-comment-id:613272644 --> @FantaBlueMystery commented on GitHub (Apr 14, 2020): Hi there Thanks for the answer! Your answer would only be a part because according to the protocol "$ ssl_preread_protocol" it would have to be divided into "TLSv1.2", "TLSv1.3", "TLSv1.1", "TLSv1.0" and the "default" for the ssh. All this would be necessary to separate the HTTPS and SSH on one port (443). If it could then be separated by domain, that would be wonderful. Would that be possible with the streams in the UI? Can you set the stream again on port 443? It would be important that only one port is present on the outside.
Author
Owner

@Thijmen commented on GitHub (Apr 14, 2020):

Is that even possible, @FantaBlueMystery ?

<!-- gh-comment-id:613363713 --> @Thijmen commented on GitHub (Apr 14, 2020): Is that even possible, @FantaBlueMystery ?
Author
Owner

@FantaBlueMystery commented on GitHub (Apr 14, 2020):

yes clearly see my first post, currently I have another nginx before npm that uses this config and on 'server 10.8.0.15:443;' forward to the npm

:)

<!-- gh-comment-id:613507244 --> @FantaBlueMystery commented on GitHub (Apr 14, 2020): yes clearly see my first post, currently I have another nginx before npm that uses this config and on 'server 10.8.0.15:443;' forward to the npm :)
Author
Owner

@gustavosbarreto commented on GitHub (May 13, 2020):

Hi @FantaBlueMystery, did you know ShellHub? I think you can configure NGINX Proxy Manager to work together ShellHub for SSH access.

I'm doing some tests with NGINX Proxy Manager and ShellHub to provide HTTPS access.

<!-- gh-comment-id:627951449 --> @gustavosbarreto commented on GitHub (May 13, 2020): Hi @FantaBlueMystery, did you know [ShellHub](https://github.com/shellhub-io/shellhub)? I think you can configure NGINX Proxy Manager to work together ShellHub for SSH access. I'm doing some tests with NGINX Proxy Manager and ShellHub to provide HTTPS access.
Author
Owner

@FantaBlueMystery commented on GitHub (May 13, 2020):

Hello @gustavosbarreto thanks for the info, I didn't know "shellhub" until now. It looks very interesting e.g. with "web-based user interface".

But here it would also be the case that it should be accessible using the SSH protocol. As an example, we would use sftp or the Ansible program.

But I'll still have a look at "shellhub". But I think to get the destination a port on the router you still can't get without the settings like in my first post.

Port 22 (or another ssh port) should not be visible from the outside. Therefore, a camouflage via https (443) is ingenious, since you can determine the HTTPs server and SSH in the internal network at the same time based on the domain (subdomaining).

<!-- gh-comment-id:627957291 --> @FantaBlueMystery commented on GitHub (May 13, 2020): Hello @gustavosbarreto thanks for the info, I didn't know "shellhub" until now. It looks very interesting e.g. with "web-based user interface". But here it would also be the case that it should be accessible using the SSH protocol. As an example, we would use sftp or the Ansible program. But I'll still have a look at "shellhub". But I think to get the destination a port on the router you still can't get without the settings like in my first post. Port 22 (or another ssh port) should not be visible from the outside. Therefore, a camouflage via https (443) is ingenious, since you can determine the HTTPs server and SSH in the internal network at the same time based on the domain (subdomaining).
Author
Owner

@ursus69 commented on GitHub (Apr 16, 2021):

Has there been any advancement on this enhancement?
It would make it the ultimate NGinx project if we could make this happen!
almost all the businesses blocks other ports than 80 and 443, so this will allow me to connect to my home undetected.
If we could also add other streams like VPN over 443 it will be great!
Cordially

<!-- gh-comment-id:821241215 --> @ursus69 commented on GitHub (Apr 16, 2021): Has there been any advancement on this enhancement? It would make it the ultimate NGinx project if we could make this happen! almost all the businesses blocks other ports than 80 and 443, so this will allow me to connect to my home undetected. If we could also add other streams like VPN over 443 it will be great! Cordially
Author
Owner

@ursus69 commented on GitHub (Apr 16, 2021):

yes clearly see my first post, currently I have another nginx before npm that uses this config and on 'server 10.8.0.15:443;' forward to the npm

:)

How do you achieve this? which docker image you use for your head Nginx with streams?
Cheers!

<!-- gh-comment-id:821242250 --> @ursus69 commented on GitHub (Apr 16, 2021): > yes clearly see my first post, currently I have another nginx before npm that uses this config and on 'server 10.8.0.15:443;' forward to the npm > > :) How do you achieve this? which docker image you use for your head Nginx with streams? Cheers!
Author
Owner

@FantaBlueMystery commented on GitHub (Apr 18, 2021):

Hey @ursus69 sorry for my late answer:

docker-compose.yml

services:
  npm:
    image: nginx
    container_name: sshproxy
    restart: always
    ports:
      - 444:443
      - 84:80
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./logs/:/var/log/nginx/

Edit your nginx.conf and add:

Can you add SSH Support? (Nice to have)

For example by my SSH-Proxy

stream {

    upstream ssh {
        server 10.8.0.16:22;
    }

    upstream https {
        server 10.8.0.15:443;
    }

    upstream https2 {
        server 10.8.0.18:443;
    }

    map $ssl_preread_server_name $name {
     mysdomain.com https2;
      default https;
    }

    map $ssl_preread_protocol $upstream {
        default ssh;
        "TLSv1.2" $name;
        "TLSv1.3" $name;
        "TLSv1.1" $name;
        "TLSv1.0" $name;
    }

    # SSH and SSL on the same port
    server {
        listen 443;

        proxy_pass $upstream;
        ssl_preread on;
    }

Simple and fast :)

<!-- gh-comment-id:822041601 --> @FantaBlueMystery commented on GitHub (Apr 18, 2021): Hey @ursus69 sorry for my late answer: docker-compose.yml ```version: "3" services: npm: image: nginx container_name: sshproxy restart: always ports: - 444:443 - 84:80 volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./logs/:/var/log/nginx/ ``` Edit your nginx.conf and add: > Can you add SSH Support? (Nice to have) > > For example by my SSH-Proxy > > ``` > stream { > > upstream ssh { > server 10.8.0.16:22; > } > > upstream https { > server 10.8.0.15:443; > } > > upstream https2 { > server 10.8.0.18:443; > } > > map $ssl_preread_server_name $name { > mysdomain.com https2; > default https; > } > > map $ssl_preread_protocol $upstream { > default ssh; > "TLSv1.2" $name; > "TLSv1.3" $name; > "TLSv1.1" $name; > "TLSv1.0" $name; > } > > # SSH and SSL on the same port > server { > listen 443; > > proxy_pass $upstream; > ssl_preread on; > } > ``` Simple and fast :)
Author
Owner

@ursus69 commented on GitHub (Apr 22, 2021):

Many thanks @FantaBlueMystery, I t works like a charm!

<!-- gh-comment-id:824583904 --> @ursus69 commented on GitHub (Apr 22, 2021): Many thanks @FantaBlueMystery, I t works like a charm!
Author
Owner

@fdelucchijr commented on GitHub (Apr 28, 2021):

This is an exiting enhancement!!! It would add an extra layer of security for my network!
Praying to see it in NPM soon!

<!-- gh-comment-id:828753846 --> @fdelucchijr commented on GitHub (Apr 28, 2021): This is an exiting enhancement!!! It would add an extra layer of security for my network! Praying to see it in NPM soon!
Author
Owner

@litio2001 commented on GitHub (Jun 8, 2021):

Do you know when this new enhancement will be available in the docker NPM image?

thanks in advance for the wonderful development!!

<!-- gh-comment-id:856470259 --> @litio2001 commented on GitHub (Jun 8, 2021): Do you know when this new enhancement will be available in the docker NPM image? thanks in advance for the wonderful development!!
Author
Owner

@chaptergy commented on GitHub (Jun 8, 2021):

I don't think this code snippet will ever be officially added to NPM unless someone creates a pull request adding this and creating a user interface where this is configurable. As it is now, this is very specific for one ssh server, and the file would have to be edited manually anyways, so there is no point in adding it. You would have to add this nginx config inside your container yourself.

<!-- gh-comment-id:856519524 --> @chaptergy commented on GitHub (Jun 8, 2021): I don't think this code snippet will ever be officially added to NPM unless someone creates a pull request adding this and creating a user interface where this is configurable. As it is now, this is very specific for one ssh server, and the file would have to be edited manually anyways, so there is no point in adding it. You would have to add this nginx config inside your container yourself.
Author
Owner

@fdelucchijr commented on GitHub (Jun 14, 2021):

I don't think this code snippet will ever be officially added to NPM unless someone creates a pull request adding this and creating a user interface where this is configurable. As it is now, this is very specific for one ssh server, and the file would have to be edited manually anyways, so there is no point in adding it. You would have to add this nginx config inside your container yourself.

This comment make me kind of sad, but its acceptable. I get an alternative.
Using Cloudflare's Argo Tunnels make this so easy! also provides TLS secure connection, IP hidding, DDNS, CGNAT Bypass and other amazing features.

For ssh with WebRender you can use this guide: This

To use the setup with the ssh cli (ProxyJump) you can use this

And, of you think this offers you a ProxyJump to far away when your locally you can use this amazing blog

KEEP IN MIND that this heavely relies in Cloudflare/LetsEncrypt DNS certificates and (in this instruction) Docker.

<!-- gh-comment-id:860927069 --> @fdelucchijr commented on GitHub (Jun 14, 2021): > > > I don't think this code snippet will ever be officially added to NPM unless someone creates a pull request adding this and creating a user interface where this is configurable. As it is now, this is very specific for one ssh server, and the file would have to be edited manually anyways, so there is no point in adding it. You would have to add this nginx config inside your container yourself. This comment make me kind of sad, but its acceptable. I get an alternative. Using Cloudflare's Argo Tunnels make this so easy! also provides TLS secure connection, IP hidding, DDNS, CGNAT Bypass and other amazing features. For ssh with WebRender you can use this guide: [This](https://github.com/aeleos/cloudflared#enabling-ssh-access-via-web-rendered-terminal) To use the setup with the ssh cli (ProxyJump) you can use [this](https://developers.cloudflare.com/cloudflare-one/tutorials/ssh#connect-from-a-client-machine) And, of you think this offers you a ProxyJump to far away when your locally you can use [this amazing blog](https://mike.place/2017/ssh-match/) KEEP IN MIND that this heavely relies in Cloudflare/LetsEncrypt DNS certificates and (in this instruction) Docker.
Author
Owner

@mriksman commented on GitHub (Oct 19, 2021):

I don't think this code snippet will ever be officially added to NPM unless someone creates a pull request adding this and creating a user interface where this is configurable. As it is now, this is very specific for one ssh server, and the file would have to be edited manually anyways, so there is no point in adding it. You would have to add this nginx config inside your container yourself.

We just need a way to enter/edit the stream block manually. Do not need a full blown GUI for it. Just click the 'Add Stream' button, have a tab that says 'Manual Entry', enter your code, and click save.

<!-- gh-comment-id:946493085 --> @mriksman commented on GitHub (Oct 19, 2021): > I don't think this code snippet will ever be officially added to NPM unless someone creates a pull request adding this and creating a user interface where this is configurable. As it is now, this is very specific for one ssh server, and the file would have to be edited manually anyways, so there is no point in adding it. You would have to add this nginx config inside your container yourself. We just need a way to enter/edit the `stream` block manually. Do not need a full blown GUI for it. Just click the 'Add Stream' button, have a tab that says 'Manual Entry', enter your code, and click save.
Author
Owner

@stefanwerfling commented on GitHub (Mar 1, 2023):

Hello everyone, I'm a big fan of NPM!

I've started to write my own software for this implementation and I'm still looking for testers, whoever is interested can take a look at the whole thing.

I'm just posting this because the idea isn't being picked up. The whole thing is still under development. I use it for myself already in a live test. You can find it through my profile.

<!-- gh-comment-id:1450355706 --> @stefanwerfling commented on GitHub (Mar 1, 2023): Hello everyone, I'm a big fan of NPM! I've started to write my own software for this implementation and I'm still looking for testers, whoever is interested can take a look at the whole thing. I'm just posting this because the idea isn't being picked up. The whole thing is still under development. I use it for myself already in a live test. You can find it through my profile.
Author
Owner

@marky421 commented on GitHub (Jan 26, 2024):

Can this feature be used to enable SSH support? Would the streams feature come into play? I'm hoping to only have ports 80/443 open on my firewall but I want to be able to SSH and host some https sites.

https://nginxproxymanager.com/advanced-config/#custom-nginx-configurations

<!-- gh-comment-id:1912620713 --> @marky421 commented on GitHub (Jan 26, 2024): Can this feature be used to enable SSH support? Would the streams feature come into play? I'm hoping to only have ports 80/443 open on my firewall but I want to be able to SSH and host some https sites. https://nginxproxymanager.com/advanced-config/#custom-nginx-configurations
Author
Owner

@stefanwerfling commented on GitHub (Jan 29, 2024):

@marky421 I do not fully understand the question.

The example above shows how an SSH protocol can be placed over the HTTPS port.
Nginx looks at which protocol applies to TLS and directs it to the appropriate upstream.
If none of the protocols match, the default target is the SSH server.

Magic :)

<!-- gh-comment-id:1914476031 --> @stefanwerfling commented on GitHub (Jan 29, 2024): @marky421 I do not fully understand the question. The example above shows how an SSH protocol can be placed over the HTTPS port. Nginx looks at which protocol applies to TLS and directs it to the appropriate upstream. If none of the protocols match, the default target is the SSH server. Magic :)
Author
Owner

@github-actions[bot] commented on GitHub (Aug 31, 2024):

Issue is now considered stale. If you want to keep it open, please comment 👍

<!-- gh-comment-id:2322727026 --> @github-actions[bot] commented on GitHub (Aug 31, 2024): Issue is now considered stale. If you want to keep it open, please comment :+1:
Author
Owner

@albeec13 commented on GitHub (Jan 24, 2025):

@

Can this feature be used to enable SSH support? Would the streams feature come into play? I'm hoping to only have ports 80/443 open on my firewall but I want to be able to SSH and host some https sites.

https://nginxproxymanager.com/advanced-config/#custom-nginx-configurations

See my reply in the linked thread here: https://github.com/NginxProxyManager/nginx-proxy-manager/issues/646#issuecomment-2613387551

tl;dr is you can use /data/nginx/custom/stream.conf to accomplish what you want, but only if you have NO other proxy hosts using 443 defined in the standard NPM GUI. You can define them usinig the OP's ssl_preread_server_name method above, but I'm not sure if that and the upstream directives are sufficient for getting ssl certs and such working for an HTTPS server without a standard http{ server { ... } } nginx block/directive.

This can, however, be easily accomplished with a standalone (non-NPM) nginx install on a linux server or small docker instance as I explain in the message linked above.

<!-- gh-comment-id:2613418613 --> @albeec13 commented on GitHub (Jan 24, 2025): @ > Can this feature be used to enable SSH support? Would the streams feature come into play? I'm hoping to only have ports 80/443 open on my firewall but I want to be able to SSH and host some https sites. > > https://nginxproxymanager.com/advanced-config/#custom-nginx-configurations See my reply in the linked thread here: https://github.com/NginxProxyManager/nginx-proxy-manager/issues/646#issuecomment-2613387551 tl;dr is you can use `/data/nginx/custom/stream.conf` to accomplish what you want, but only if you have NO other proxy hosts using 443 defined in the standard NPM GUI. You can define them usinig the OP's `ssl_preread_server_name` method above, but I'm not sure if that and the `upstream` directives are sufficient for getting ssl certs and such working for an HTTPS server without a standard `http{ server { ... } }` nginx block/directive. This can, however, be easily accomplished with a standalone (non-NPM) nginx install on a linux server or small docker instance as I explain in the message linked above.
Author
Owner

@stefanwerfling commented on GitHub (Jan 26, 2025):

@albeec13 Why are you reposting an answer that has been clarified for a long time? Your example, which came later, explains the same context.

It's clear that if npm doesn't build an interface for this, this issue will only be closed if it is rejected. That's okay too. Then you can put your own config or a pre-nginx in front of it.

:)

<!-- gh-comment-id:2614313419 --> @stefanwerfling commented on GitHub (Jan 26, 2025): @albeec13 Why are you reposting an answer that has been clarified for a long time? Your example, which came later, explains the same context. It's clear that if npm doesn't build an interface for this, this issue will only be closed if it is rejected. That's okay too. Then you can put your own config or a pre-nginx in front of it. :)
Author
Owner

@albeec13 commented on GitHub (Jan 27, 2025):

@albeec13 Why are you reposting an answer that has been clarified for a long time? Your example, which came later, explains the same context.

It's clear that if npm doesn't build an interface for this, this issue will only be closed if it is rejected. That's okay too. Then you can put your own config or a pre-nginx in front of it.

:)

I was running into a similar problem and decided to respond to this existing thread instead of starting a new one. Moreover, there were two important distinctions between my response and others I've seen which are:

  1. You can accomplish ssh/tls at the same time on a single server without needing to run another instance of nginx
  2. If you decide to use ./custom/stream.conf, you will not be able to use other proxy hosts on 443 from the normal GUI route in NPM

I felt these were important/useful to the next person who may run into this issue. If it's not of use to you, no need to snark about it.

<!-- gh-comment-id:2616978555 --> @albeec13 commented on GitHub (Jan 27, 2025): > [@albeec13](https://github.com/albeec13) Why are you reposting an answer that has been clarified for a long time? Your example, which came later, explains the same context. > > It's clear that if npm doesn't build an interface for this, this issue will only be closed if it is rejected. That's okay too. Then you can put your own config or a pre-nginx in front of it. > > :) I was running into a similar problem and decided to respond to this existing thread instead of starting a new one. Moreover, there were two important distinctions between my response and others I've seen which are: 1. You can accomplish ssh/tls at the same time on a _single server_ without needing to run another instance of nginx 2. If you decide to use `./custom/stream.conf`, you will not be able to use other proxy hosts on 443 from the normal GUI route in NPM I felt these were important/useful to the next person who may run into this issue. If it's not of use to you, no need to snark about it.
Author
Owner

@stefanwerfling commented on GitHub (Jan 28, 2025):

@albeec13 Okay, I understand, then we got off on the wrong foot.

I'm not sure if that and the upstream directives are sufficient for getting ssl certs and such working for an HTTPS server without a standard http{ server { ... } } nginx block/directive.

Apart from npm, this is possible and this is also what my app is aiming for.

As with the 443 port, you also carry out “domain splitting” on the 80 port, i.e. a map to different upstreams. For example, all domains that point to the 80 port are directed to the upstream 127.0.0.1:10080.

There the 10080 waits for a response depending on the domain with

server {
    listen 10080;
    ...
}

each of these "servers" has a location /.well-know/ entry.

Now you could ask yourself how the original client IP gets to the server.

This is also easy, in the

stream {
   server {
      ...
      proxy_protocol on;
   }
}

"proxy_protocol" is activated and on the

http {
   server {
      listen 10080 proxy_protocol;
   }
}

Activated. Now the client IPs will also be passed on.

<!-- gh-comment-id:2618540067 --> @stefanwerfling commented on GitHub (Jan 28, 2025): @albeec13 Okay, I understand, then we got off on the wrong foot. > I'm not sure if that and the upstream directives are sufficient for getting ssl certs and such working for an HTTPS server without a standard http{ server { ... } } nginx block/directive. Apart from npm, this is possible and this is also what my app is aiming for. As with the 443 port, you also carry out “domain splitting” on the 80 port, i.e. a map to different upstreams. For example, all domains that point to the 80 port are directed to the upstream 127.0.0.1:10080. There the 10080 waits for a response depending on the domain with ``` server { listen 10080; ... } ``` each of these "servers" has a location /.well-know/ entry. Now you could ask yourself how the original client IP gets to the server. This is also easy, in the ``` stream { server { ... proxy_protocol on; } } ``` "proxy_protocol" is activated and on the ``` http { server { listen 10080 proxy_protocol; } } ``` Activated. Now the client IPs will also be passed on.
Author
Owner

@albeec13 commented on GitHub (Jan 28, 2025):

@albeec13 Okay, I understand, then we got off on the wrong foot.

No worries!

I'm not sure if that and the upstream directives are sufficient for getting ssl certs and such working for an HTTPS server without a standard http{ server { ... } } nginx block/directive.

Apart from npm, this is possible and this is also what my app is aiming for.

I'll have to check that out, thanks!

As with the 443 port, you also carry out “domain splitting” on the 80 port, i.e. a map to different upstreams. For example, all domains that point to the 80 port are directed to the upstream 127.0.0.1:10080.

There the 10080 waits for a response depending on the domain with

server {
    listen 10080;
    ...
}

each of these "servers" has a location /.well-know/ entry.

Now you could ask yourself how the original client IP gets to the server.

This is also easy, in the

stream {
   server {
      ...
      proxy_protocol on;
   }
}

"proxy_protocol" is activated and on the

http {
   server {
      listen 10080 proxy_protocol;
   }
}

Activated. Now the client IPs will also be passed on.

Cool, I was not aware of the proxy_protocol directive, I'll need to look into that some more. Thanks!

<!-- gh-comment-id:2620192459 --> @albeec13 commented on GitHub (Jan 28, 2025): > [@albeec13](https://github.com/albeec13) Okay, I understand, then we got off on the wrong foot. No worries! > > > I'm not sure if that and the upstream directives are sufficient for getting ssl certs and such working for an HTTPS server without a standard http{ server { ... } } nginx block/directive. > > Apart from npm, this is possible and this is also what my app is aiming for. I'll have to check that out, thanks! > > As with the 443 port, you also carry out “domain splitting” on the 80 port, i.e. a map to different upstreams. For example, all domains that point to the 80 port are directed to the upstream 127.0.0.1:10080. > > There the 10080 waits for a response depending on the domain with > > ``` > server { > listen 10080; > ... > } > ``` > > each of these "servers" has a location /.well-know/ entry. > > Now you could ask yourself how the original client IP gets to the server. > > This is also easy, in the > > ``` > stream { > server { > ... > proxy_protocol on; > } > } > ``` > > "proxy_protocol" is activated and on the > > ``` > http { > server { > listen 10080 proxy_protocol; > } > } > ``` > > Activated. Now the client IPs will also be passed on. Cool, I was not aware of the proxy_protocol directive, I'll need to look into that some more. Thanks!
Author
Owner

@komodikkio commented on GitHub (May 21, 2025):

I'm trying to achieve this using a custom/stream.conf, but looks like i'm missing something.
When i try to connect via ssh -p 443 i get this errors:

debug1: kex_exchange_identification: banner line 0: HTTP/1.1 400 Bad Request
debug1: kex_exchange_identification: banner line 1: Server: openresty
debug1: kex_exchange_identification: banner line 2: Date: Wed, 21 May 2025 15:08:03 GMT
debug1: kex_exchange_identification: banner line 3: Content-Type: text/html
debug1: kex_exchange_identification: banner line 4: Content-Length: 154
debug1: kex_exchange_identification: banner line 5: Connection: close
debug1: kex_exchange_identification: banner line 6:
debug1: kex_exchange_identification: banner line 7: <html>
debug1: kex_exchange_identification: banner line 8: <head><title>400 Bad Request</title></head>
debug1: kex_exchange_identification: banner line 9: <body>
debug1: kex_exchange_identification: banner line 10: <center><h1>400 Bad Request</h1></center>
debug1: kex_exchange_identification: banner line 11: <hr><center>openresty</center>
debug1: kex_exchange_identification: banner line 12: </body>
debug1: kex_exchange_identification: banner line 13: </html>

This is my custom/stream.conf file, for the ssh upstream i use the docker IP which i can connect to using the shell from the NPM container:

cat /data/compose/2/data/nginx/custom/stream.conf
    upstream ssh {
        server 172.17.30.1:8443;  
    }

    upstream https {
        server 10.8.0.15:443;
    }

    upstream https2 {
        server 10.8.0.18:443;
    }

    map $ssl_preread_server_name $name {
     default ssh;
     mysdomain.com https2;
    }

    map $ssl_preread_protocol $upstream {
        default ssh;
        "TLSv1.2" $name;
        "TLSv1.3" $name;
        "TLSv1.1" $name;
        "TLSv1.0" $name;
    }

    # SSH and SSL on the same port
    server {
        listen 443;

        proxy_pass $upstream;
        ssl_preread on;
    }

Thanks a lot for any help you can give me, it'll be really appreciated

@albeec13
I was running into a similar problem and decided to respond to this existing thread instead of starting a new one. Moreover, there were two important distinctions between my response and others I've seen which are:

  1. You can accomplish ssh/tls at the same time on a single server without needing to run another instance of nginx
  2. If you decide to use ./custom/stream.conf, you will not be able to use other proxy hosts on 443 from the normal GUI route in NPM

I felt these were important/useful to the next person who may run into this issue. If it's not of use to you, no need to snark about it.

<!-- gh-comment-id:2898345010 --> @komodikkio commented on GitHub (May 21, 2025): I'm trying to achieve this using a custom/stream.conf, but looks like i'm missing something. When i try to connect via ssh -p 443 i get this errors: ``` debug1: kex_exchange_identification: banner line 0: HTTP/1.1 400 Bad Request debug1: kex_exchange_identification: banner line 1: Server: openresty debug1: kex_exchange_identification: banner line 2: Date: Wed, 21 May 2025 15:08:03 GMT debug1: kex_exchange_identification: banner line 3: Content-Type: text/html debug1: kex_exchange_identification: banner line 4: Content-Length: 154 debug1: kex_exchange_identification: banner line 5: Connection: close debug1: kex_exchange_identification: banner line 6: debug1: kex_exchange_identification: banner line 7: <html> debug1: kex_exchange_identification: banner line 8: <head><title>400 Bad Request</title></head> debug1: kex_exchange_identification: banner line 9: <body> debug1: kex_exchange_identification: banner line 10: <center><h1>400 Bad Request</h1></center> debug1: kex_exchange_identification: banner line 11: <hr><center>openresty</center> debug1: kex_exchange_identification: banner line 12: </body> debug1: kex_exchange_identification: banner line 13: </html> ``` This is my custom/stream.conf file, for the ssh upstream i use the docker IP which i can connect to using the shell from the NPM container: ``` cat /data/compose/2/data/nginx/custom/stream.conf upstream ssh { server 172.17.30.1:8443; } upstream https { server 10.8.0.15:443; } upstream https2 { server 10.8.0.18:443; } map $ssl_preread_server_name $name { default ssh; mysdomain.com https2; } map $ssl_preread_protocol $upstream { default ssh; "TLSv1.2" $name; "TLSv1.3" $name; "TLSv1.1" $name; "TLSv1.0" $name; } # SSH and SSL on the same port server { listen 443; proxy_pass $upstream; ssl_preread on; } ``` Thanks a lot for any help you can give me, it'll be really appreciated > > [@albeec13](https://github.com/albeec13) > I was running into a similar problem and decided to respond to this existing thread instead of starting a new one. Moreover, there were two important distinctions between my response and others I've seen which are: > > 1. You can accomplish ssh/tls at the same time on a _single server_ without needing to run another instance of nginx > 2. If you decide to use `./custom/stream.conf`, you will not be able to use other proxy hosts on 443 from the normal GUI route in NPM > > I felt these were important/useful to the next person who may run into this issue. If it's not of use to you, no need to snark about it.
Author
Owner

@stefanwerfling commented on GitHub (May 22, 2025):

@komodikkio

I've created an overview of the route for you. If no suitable domain is specified, your browser will default to "ssh," which it won't be able to do (it won't understand because it's an SSH protocol). "https" upstream is empty and cannot be reached.

Image

On the upstream "ssh," I see that you're specifying port "8443," which not sounds like the SSH server. Please check this again; the normal SSH port is 22. If there's a web server behind 8443, it won't understand SSH and will respond with a "Bad Request."

I hope this helps you.

<!-- gh-comment-id:2900529101 --> @stefanwerfling commented on GitHub (May 22, 2025): @komodikkio I've created an overview of the route for you. If no suitable domain is specified, your browser will default to "ssh," which it won't be able to do (it won't understand because it's an SSH protocol). "https" upstream is empty and cannot be reached. ![Image](https://github.com/user-attachments/assets/10ca53f3-ce8d-4fba-a57e-67abb75a14b3) On the upstream "ssh," I see that you're specifying port "8443," which not sounds like the SSH server. Please check this again; the normal SSH port is 22. If there's a web server behind 8443, it won't understand SSH and will respond with a "Bad Request." I hope this helps you.
Author
Owner

@komodikkio commented on GitHub (May 22, 2025):

Hi Stefan, thanks for the provided oveview.
What is failing to me it's the ssh connection when i call, from public, the NPM's port 443
When i try to ssh to mypublic ip:443 i get this 400 Bad Request output on the ssh shell.

On the ssh upstream i specified the 8443 port because the service it's listening on a custom port :)
netstat -tunlp |grep 8443
tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN 26969/sshd: /usr/sb

At the momento i'm not trying to reach an https service via browser, i'm trying just the SSH connection

Thanks again for getting back to me

@komodikkio

I've created an overview of the route for you. If no suitable domain is specified, your browser will default to "ssh," which it won't be able to do (it won't understand because it's an SSH protocol). "https" upstream is empty and cannot be reached.

Image

On the upstream "ssh," I see that you're specifying port "8443," which not sounds like the SSH server. Please check this again; the normal SSH port is 22. If there's a web server behind 8443, it won't understand SSH and will respond with a "Bad Request."

I hope this helps you.

<!-- gh-comment-id:2900649418 --> @komodikkio commented on GitHub (May 22, 2025): Hi Stefan, thanks for the provided oveview. What is failing to me it's the ssh connection when i call, from public, the NPM's port 443 When i try to ssh to mypublic ip:443 i get this 400 Bad Request output on the ssh shell. On the ssh upstream i specified the 8443 port because the service it's listening on a custom port :) netstat -tunlp |grep 8443 tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN 26969/sshd: /usr/sb At the momento i'm not trying to reach an https service via browser, i'm trying just the SSH connection Thanks again for getting back to me > [@komodikkio](https://github.com/komodikkio) > > I've created an overview of the route for you. If no suitable domain is specified, your browser will default to "ssh," which it won't be able to do (it won't understand because it's an SSH protocol). "https" upstream is empty and cannot be reached. > > ![Image](https://github.com/user-attachments/assets/10ca53f3-ce8d-4fba-a57e-67abb75a14b3) > > On the upstream "ssh," I see that you're specifying port "8443," which not sounds like the SSH server. Please check this again; the normal SSH port is 22. If there's a web server behind 8443, it won't understand SSH and will respond with a "Bad Request." > > I hope this helps you.
Author
Owner

@stefanwerfling commented on GitHub (May 22, 2025):

@komodikkio
Then we have to check everything individually to see where the problem lies :) :

  1. SSH funktioniert direct with 172.17.30.1:8443 ?
  2. nginx from NPM is loading /custom/stream.conf?
    2.1 Is there perhaps another server with 443? Try using a different port, 1443, and test that.
    2.2 Try "https2" with a different web server, does a different page appear in the browser?

Based on the answer, we can rule out whether there is another configuration for the 443

<!-- gh-comment-id:2900730699 --> @stefanwerfling commented on GitHub (May 22, 2025): @komodikkio Then we have to check everything individually to see where the problem lies :) : 1. SSH funktioniert direct with 172.17.30.1:8443 ? 2. nginx from NPM is loading /custom/stream.conf? 2.1 Is there perhaps another server with 443? Try using a different port, 1443, and test that. 2.2 Try "https2" with a different web server, does a different page appear in the browser? Based on the answer, we can rule out whether there is another configuration for the 443
Author
Owner

@komodikkio commented on GitHub (May 22, 2025):

@stefanwerfling
here's the test's results
1 Yes, ssh reply if i try to connect from NPM's container to the ip:8443 port
2 in the container i can find the stream config under the /data/nginx/custom/stream.conf file. Does this mean it has been loaded, right?
2.1 there's something else exposed by NPM on 443 port, but i can't figure what

Running netstat on the host:

netstat -tunlp |grep 443
tcp        0      0 0.0.0.0:9443            0.0.0.0:*               LISTEN      1254/docker-proxy
tcp        0      0 0.0.0.0:8443            0.0.0.0:*               LISTEN      23356/sshd: /usr/sb
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      23992/docker-proxy

If i try to open it, from the host or from the container, using the browser or curl, i get an error:

curl -vvv https://localhost
*   Trying 127.0.0.1:443...
* Connected to localhost (127.0.0.1) port 443 (#0)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS alert, unrecognized name (624):
* OpenSSL/3.0.15: error:0A000458:SSL routines::tlsv1 unrecognized name
* Closing connection 0
curl: (35) OpenSSL/3.0.15: error:0A000458:SSL routines::tlsv1 unrecognized name

On the 80/tcp port i find the default page of nginx stating: "Congratulations! You've successfully started the Nginx Proxy Manager."
I think there's something like a default nginx page defined somewhere also for 443/tcp, but can't find it, and maybe the unrecognized name arise because there's not a SSL cert configured anywhere

2.2 tryed to map http2 to the NPM management page at :81, but can't get it work. I think because that's http only

I don't know what's going on but i'm thinking that, even if I could make it work, loosing the chance to use NPM's gui for managing websites and SSL certificates makes it a bit "wasted"

<!-- gh-comment-id:2901083574 --> @komodikkio commented on GitHub (May 22, 2025): @stefanwerfling here's the test's results 1 Yes, ssh reply if i try to connect from NPM's container to the ip:8443 port 2 in the container i can find the stream config under the /data/nginx/custom/stream.conf file. Does this mean it has been loaded, right? 2.1 there's something else exposed by NPM on 443 port, but i can't figure what Running netstat on the host: ``` netstat -tunlp |grep 443 tcp 0 0 0.0.0.0:9443 0.0.0.0:* LISTEN 1254/docker-proxy tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN 23356/sshd: /usr/sb tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 23992/docker-proxy ``` If i try to open it, from the host or from the container, using the browser or curl, i get an error: ``` curl -vvv https://localhost * Trying 127.0.0.1:443... * Connected to localhost (127.0.0.1) port 443 (#0) * ALPN: offers h2,http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.3 (IN), TLS alert, unrecognized name (624): * OpenSSL/3.0.15: error:0A000458:SSL routines::tlsv1 unrecognized name * Closing connection 0 curl: (35) OpenSSL/3.0.15: error:0A000458:SSL routines::tlsv1 unrecognized name ``` On the 80/tcp port i find the default page of nginx stating: "Congratulations! You've successfully started the Nginx Proxy Manager." I think there's something like a default nginx page defined somewhere also for 443/tcp, but can't find it, and maybe the unrecognized name arise because there's not a SSL cert configured anywhere 2.2 tryed to map http2 to the NPM management page at :81, but can't get it work. I think because that's http only I don't know what's going on but i'm thinking that, even if I could make it work, loosing the chance to use NPM's gui for managing websites and SSL certificates makes it a bit "wasted"
Author
Owner

@stefanwerfling commented on GitHub (May 22, 2025):

@komodikkio
Okay, if you don't want to destroy the NPM 443 config, you'll have to move this server to a different port, 9443. I've made you another diagram.

Image

Process: The router redirects the 443 port from the public IP to 9443, which splits the protocol and redirects it internally to 443. 443 is not listed externally (it is not published in Docker).

map $ssl_preread_server_name $name {
     default ssh;
     mysdomain.com https2;
    }

$ssl_preread_server_nam You can leave it out, because It is take care of the names, unless you have a server that issues itself a certificate with Let's Encrypt, in which case you'll need this block. Then you can also point it to your NPM 443 by default.

Problem: You now have 9443 as your pre-proxy, so you're losing the client's IP address because the server always shows 127.0.0.1 as the client's IP address. To fix this, you need to enable the proxy protocol. The link tells you what you need to do. But you'll also need to find the 443 config again, where you configure it so that you now receive everything with the proxy protocol header.

https://github.com/NginxProxyManager/nginx-proxy-manager/issues/344#issuecomment-2618540067

good luck! :)

<!-- gh-comment-id:2901172131 --> @stefanwerfling commented on GitHub (May 22, 2025): @komodikkio Okay, if you don't want to destroy the NPM 443 config, you'll have to move this server to a different port, 9443. I've made you another diagram. ![Image](https://github.com/user-attachments/assets/88bbca5a-e2f5-4ff6-8898-738b8b2fba89) Process: The router redirects the 443 port from the public IP to 9443, which splits the protocol and redirects it internally to 443. 443 is not listed externally (it is not published in Docker). ``` map $ssl_preread_server_name $name { default ssh; mysdomain.com https2; } ``` $ssl_preread_server_nam You can leave it out, because It is take care of the names, unless you have a server that issues itself a certificate with Let's Encrypt, in which case you'll need this block. Then you can also point it to your NPM 443 by default. **Problem:** You now have 9443 as your pre-proxy, so you're losing the client's IP address because the server always shows 127.0.0.1 as the client's IP address. To fix this, you need to enable the proxy protocol. The link tells you what you need to do. But you'll also need to find the 443 config again, where you configure it so that you now receive everything with the proxy protocol header. https://github.com/NginxProxyManager/nginx-proxy-manager/issues/344#issuecomment-2618540067 good luck! :)
Author
Owner

@komodikkio commented on GitHub (May 22, 2025):

Thanks @stefanwerfling that would be great.
Sadly i'm on oracle cloud free tier, so i can't do port forwarding but just open/close a port.
I could try to enable the port forwarding on the host itsaelf using iptables

<!-- gh-comment-id:2901456121 --> @komodikkio commented on GitHub (May 22, 2025): Thanks @stefanwerfling that would be great. Sadly i'm on oracle cloud free tier, so i can't do port forwarding but just open/close a port. I could try to enable the port forwarding on the host itsaelf using iptables
Author
Owner

@github-actions[bot] commented on GitHub (Dec 9, 2025):

Issue is now considered stale. If you want to keep it open, please comment 👍

<!-- gh-comment-id:3629899168 --> @github-actions[bot] commented on GitHub (Dec 9, 2025): Issue is now considered stale. If you want to keep it open, please comment :+1:
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/nginx-proxy-manager-NginxProxyManager#303
No description provided.