fbpx

Server Setup

NGINX: putting multiple services on the same port

by , , revisited on


We have by far the largest RPM repository with NGINX module packages and VMODs for Varnish. If you want to install NGINX, Varnish, and lots of useful performance/security software with smooth yum upgrades for production use, this is the repository for you.
Active subscription is required.

Recent versions of NGINX introduce the TLS pre-read capabilities, which allow it to see which TLS protocols are supported by the client, the requested SNI server name, and the ALPN protocol of request. All this information, known before the request is routed by NGINX to the upstream servers, makes it possible to conditionally route requests to different services while using the same port.

In the following example config, we allow connections to SSH, MTProxy, and a TLS encrypted website, all through the same machine, same IP, and the same port, 443.

SSH

The SSH has no relation to TLS encryption, but it can be tought to go through TLS connection using the ProxyCommand option:

ssh username@host.example.com -o "ProxyCommand openssl s_client -alpn identifyssh -ign_eof -quiet -connect host.example.com:443"

Where identifyssh is an arbitrary string we use for ALPN protocol specification that will be picked up in our NGINX config to selectively route requests to actual SSH port on the remote machine, 22.

MTProxy

MTProxy can do “Fake TLS”. Since the client will not advertise itself with a unique ALPN protocol, the way to selectively route traffic for it, as making it the “default” route, while having the web route check the server name requested via SNI.

Propagating remote IP addresses for web logs

Note that the only downside of this configuration is due to MTProxy failure when PROXY protocol V2 is enabled in the traffic director. This yields web logs containing only local address 127.0.0.1.

It would be easily solved if NGINX supported variable value for proxy_protocol directive. However, this is not the case at the time of this writing.

The proxy_bind directive is a solution which allows spoofing remote address all the way throughout NGINX configuration (proxy_bind $remote_addr transparent;). However to make it work, it requires you to configure routing in Linux.

stream {

    # check ALPN for xmpp client or server and redirect to local ssl termination endpoints
    map $ssl_preread_alpn_protocols $upstream_by_proto {
        "identifyssh"     127.0.0.1:8022;
        default           127.0.0.1:8443;
    }

    map $ssl_preread_server_name $upstream {
        "host.example.com" 127.0.0.1:8080;
        default           $upstream_by_proto;
    }

    # Traffic director server
    server {
        listen 443;
        ssl_preread on;
        proxy_ssl off;
        proxy_pass $upstream;
        # proxy_protol breaks mtproxy, it does not support variable
        # see above for the solution
        # proxy_protocol on;
        set_real_ip_from  172.18.0.0/32;
    }

    # TLS termination for SSH connections
    server {
        listen 8022 ssl;
        ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
        ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
        ssl_dhparam /etc/ssl/certs/dhparam.pem;
        proxy_ssl off;
        proxy_pass 127.0.0.1:22;
    }
}

Actual services running locally:

  • MTProxy on port 8443.
  • SSH on port 22
  • TLS website on port 8080, via listen 8080 ssl;

Helper server blocks:

  • The server with listen 443; is our dispatcher. It routes to either actual or helper server block, depending on the constructed $upstream variable value. It pre-reads SSL information from requests via ssl_preread on;, but does not do any TLS encryption by itself (proxy_ssl off;), allowing the upstram configuration whether the TLS encryption needs to be done.
  • The server with listen 8022 ssl; is an intermediate for our SSH connections, it makes them “TLS aware”, by doing TLS encryption and then routing request to actual SSH port

References

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.