Running SSL and Non-SSL Protocols over the Same Port with NGINX 1.15.2

Faisal Memon Thumbnail
Faisal Memon
Published July 24, 2018

Today we are pleased to announce the availability of NGINX Open Source 1.15.2. One key feature in this release is the new $ssl_preread_protocol variable, which allows you to distinguish between SSL/TLS and other protocols when forwarding traffic using a TCP (stream) proxy. This is useful if you want to avoid firewall restrictions by (for example) running SSL/TLS and SSH services on the same port.

The new feature will also be available to NGINX Plus customers in the upcoming NGINX Plus R16 release.

When and How to Use $ssl_preread_protocol

When you terminate and decrypt SSL/TLS traffic, with either the http or stream modules, the $ssl_protocol (http, stream) variable captures the version of SSL or TLS used by the client. However, sometimes you might wish to simply forward SSL/TLS traffic without decrypting it, using the stream modules to implement a basic TCP proxy or load balancer.

The stream_ssl_preread module inspects the initial ClientHello message in an SSL or TLS connection, and extracts several values which can be used to manage the connection. The $ssl_preread_protocol variable added in release 1.15.2 captures the latest SSL/TLS version number from the client_version field of the ClientHello message. If the supported_versions extension is present in the ClientHello message, then the variable is set to TLSv1.3.

If a connection does not use a version of SSL or TLS, the $ssl_preread_protocol variable will be blank, indicating that the connection is using a protocol other than SSL/TLS, such as SSH.

The following configuration snippet uses the $ssl_preread_protocol variable in a map block to set the $upstream variable to the name of the upstream group appropriate for the protocol being used on the connection. The proxy_pass directive then forwards the request to the selected upstream group. Note that the ssl_preread on directive must be included in the server block for the $ssl_preread_protocol variable to work.

stream {    upstream ssh {

    upstream web {

    map $ssl_preread_protocol $upstream {
        default ssh;
        "TLSv1.2" web;

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

        proxy_pass $upstream;
        ssl_preread on;

For the configuration to be effective, clients need to access the SSH server on port 443 instead of the default port 22. With the built‑in SSH client on MacOS and Linux, for example, you can use the -p flag to change the port:

$ ssh ssh-server-ip-address -p 443

How to Get the Latest NGINX Version

The latest version of NGINX is always available in the mainline branch of our official repository.

Learn More

NGINX Open Source 1.15.2 contains additional enhancements and bug fixes. For a full list of what’s new, see the NGINX change log.

"This blog post may reference products that are no longer available and/or no longer supported. For the most current information about available F5 NGINX products and solutions, explore our NGINX product family. NGINX is now part of F5. All previous links will redirect to similar NGINX content on"