francoismichel / ssh3

SSH3: faster and rich secure shell using HTTP/3, checkout our article here: https://arxiv.org/abs/2312.08396 and our Internet-Draft: https://datatracker.ietf.org/doc/draft-michel-ssh3/
https://arxiv.org/abs/2312.08396
Apache License 2.0
3.18k stars 81 forks source link

Any concept/idea to share with NGINX/SSL port 443? #97

Closed mikeggh closed 5 months ago

mikeggh commented 5 months ago

Is there any way, or prior engineering put into sharing a port such as SSL/nginx to allow the 'secret path' to connect?

mpiraux commented 5 months ago

For authentication to pass thru a proxy such as NGINX, some modifications to the protocol has to be made. Currently the authentication is tied to the QUIC connection authentication, which breaks the proxy model. François has started working on this here, https://github.com/francoismichel/ssh3/pull/89, and more details are available there.

Also, this might be a duplicate of #67.

francoismichel commented 5 months ago

You currently can already use nginx to do multiplexing based on the server name (not the URI path parameter yet), all you need is nginx version 1.25.3 (with http3 support) and you just need to configure it to proxy QUIC connections towards your ssh3 server based on the server name you chose.

For instance, let's say you have the hostname example.org. You have nginx listening on the UDP open port 443 on your machine and you have your SSH3 server listening on port 4444. You can attribute the ssh3.example.org server name to your ssh3 server (you need the certificate for it).

If you have all that configured, you can do something like below in your nginx config and it should work:

stream {
        map $ssl_preread_server_name $name {
            ssh3.example.org   ssh3;
        }

        upstream ssh3 {
            server 127.0.0.1:443;
        }

        server {
            listen      443 udp;
            proxy_pass  ssh3;
            ssl_preread on;
        }
}

And you can add other HTTP/3 services by adding other upstreams and adding them in the map.

This is not explicitly discussed in the nginx doc, but the following ref may still help you: https://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html

The advantage of that solution is that the proxy does not decrypt your traffic and therefore does not have to be trusted. The disadvantage is that is is less flexible.

francoismichel commented 5 months ago

For reverse proxies support (i.e. ones that decrypt the HTTP requests and handle stuff basd on the actual requests), we need more time for quic implementations and HTTP/3 standardisation to move forward:

So it is coming and it will be really nice as we'll be able to run several SSH3 connections with isolated authentication contects over the same HTTP/3 connection, but we need to wait a bit for reverse proxies.

mikeggh commented 5 months ago

Thanks abunch! I'll give it a shot!

ScreenSurfer commented 2 months ago

any update on this guys ? did this worked properly ?

francoismichel commented 2 months ago

Hi ! The easiest way to do that would be to rely on SNI multiplexing as it does not require implementing a terminating proxy. Currently, nginx does not support SNI forwarding (I thought it did, but it actually doesn't). That being said, I recently implemented SNI multiplexing on top of Caddy as a layer4 plugin. It works, I will clean up the code and release it in the coming days (it is still experimental but already works well for domestic use case).

So if I'm not missing anything, Caddy will probably be the first Open Source server implementation that has QUIC SNI multiplexing. This means you can co-locate ssh3 and your other web servers. I'm already doing it right now. :-)

Right now, the Caddy plugin requires a fork of caddy-l4 as long as an important PR for UDP is not merged (https://github.com/mholt/caddy-l4/pull/141).

jkhsjdhjs commented 1 month ago

Currently, nginx does not support SNI forwarding (I thought it did, but it actually doesn't).

It actually does via the ngx_stream_ssl_preread module, which provides the $ssl_preread_server_name variable.

https://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html