0

I have one public IP address. I am trying to allow access via the public IP on ports 80 and 443 to multiple services, differentiated by requested server name.

HOWEVER, one service requires a TCP reverse proxy on ports 80 and 443 on the public IP to operate. Another requires TCP reverse proxy but just on port 443. The rest are just websites and fine with an http reverse proxy, but I want the websites publicly accessible on ports 80 and 443 to make it easy for visitors and for letsencrypt.

I can spin up as many VM's and private IP's as necessary to keep it simple, but limited to the one public IP address.

Can I do this with nginx setup as a reverse proxy using SNI? In theory I think I should be able to tcp stream everything by hostname using SNI directed to the appropriate server, with a second webserver that has the required websites setup to listen on different ports. For example, nginx.conf:

stream {
map $ssl_preread_server_name $name {
        serviceone.domain.tld serviceone;
        servicetwo.domain.tld servicetwo;
        website1.domain.tld website1;       
        website2.domain.tld website2;   
}

upstream serviceone {
        server 10.1.99.7:443;
}

upstream servicetwo {
        server 10.1.99.20:443;
}

upstream website1 {
        server 10.1.99.30:10443;
}

upstream website2 {
        server 10.1.99.30:10444;
}


server {
        listen 443;
        listen 80;
        resolver 8.8.8.8;

        proxy_pass $name;
        ssl_preread on;
}

}

I have something working similar to the above in my nginx.conf, but am struggling a bit with understanding how port 80 requests come into the equation (I just slapped listen 80 in the server block, but could not explain how requests are handled in terms of differentiating between 443 and 80 if the same server name is requested)

I am open to better ways of doing it also using nginx or haproxy etc. Thanks!

Blair
  • 1
  • 1

1 Answers1

0

Just use seperate server{...} blocks for each hostname.

It does the job without a dependency on an additional module and will save you a LOT of pain if the upstream servers differ in the configuration required on the proxy.

symcbean
  • 22,376
  • I have setup another server block for port 80, and simplified the config. However, all port 80 traffic goes to the 'default' map {..} I have added. It appears that $ssl_preread_server_name is not populated for http traffic. So apparently for tcp streaming which is layer 4 I can't use server_name, except if it is https in which case SNI comes to the rescue and I can? – Blair Sep 19 '23 at 03:54
  • Sorry - should have said Just use seperate server{...} blocks for each hostname + scheme. DO NOT use maps for this. nginx will use SNI for TLS and the HTTP header for HTTP. The handling for _default is (IME) a little buggy in some versions of nginx - just omit the default host or look at the order of loading of the files. – symcbean Sep 19 '23 at 08:39
  • Thanks. I changed the config to use one upstream { ... } directive for each hostname, then proxy_pass $ssl_preread_server_name in the listener on 443. But for the server { listen 80... } block, I don't understand how I can access the server_name? Everything I read says that within the stream context there is no concept of server_name except for SNI – Blair Sep 20 '23 at 02:58
  • Its in the HTTP header - nginx can't read the the HTTP header over TLS until it has negotiated a connection so it needs to know what hostname is being requested BEFORE the connection is established, hence SNI. OTOH with plain old HTTP it can read the header THEN decide which vhost should handle the request. – symcbean Sep 20 '23 at 09:03
  • My understanding is that in the http {} context nginx reads the http header, but in the stream {} context it does not. If you know of a variable or function available within the stream { } context that lets me get to the http header, please let me know. – Blair Sep 20 '23 at 20:20
  • Nginx config might look like code. Its not. – symcbean Sep 21 '23 at 08:03
  • That's good, because I am not a coder! Apologies if I am not using the correct terminology in my messages though - I'm doing my best, but I am new to nginx. Conceptually I don't understand how nginx is able to read http headers if it is tcp proxying. No worries if you don't have time to help. – Blair Sep 21 '23 at 21:30