Raymii.org
Quis custodiet ipsos custodes?Home | About | All pages | Cluster Status | RSS Feed
nginx 1.15.2, ssl_preread_protocol, multiplex HTTPS and SSH on the same port
Published: 06-08-2018 | Last update: 12-01-2020 | Author: Remy van Elst | Text only version of this article
❗ This post is over three years old. It may no longer be up to date. Opinions may have changed.
Table of Contents
The NGINX blog recently had a nice article on a new feature of NGINX 1.15.2, $ssl preread protocol. This allows you to multiplex HTTPS and other SSL protocols on the same port, or as their blog states, 'to distinguish between SSL/TLS and other protocols when forwarding traffic using a TCP (stream) proxy'. This can be used to run SSH and HTTPS on the same port (or any other SSL protocol next to HTTPS). By running SSH and HTTPS on the same port, one can circumvent certain firewall restrictions. If the session looks like HTTPS, nginx will handle it, if it looks like something else, it will forward it to the configured other program. I used to use SSLH to get this functionality, but now it's built into the nginx webserver.
Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:
I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go check it out!
Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.
You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $200 credit for 60 days. Spend $25 after your credit expires and I'll get $25!
This small guide will cover the installation of the latest version of nginx on Ubuntu and configuring this multiplex feature.
You must use NGINX in proxy mode. This means that nginx will act as a load balancer or proxy in front of your application (like Django, Rails, etc).
- Update 12-01-2020: added apt-key add. Added example of ssh and https on the same server.
Install the latest version of NGINX
nginx provides a repository for both CentOS, Debian/Ubuntu and SUSE. In this example we will use Ubuntu.
Download the signing key:
wget http://nginx.org/keys/nginx_signing.key
Trust the signing key:
apt-key add nginx_signing.key
Add the repository:
echo "deb http://nginx.org/packages/mainline/ubuntu/ bionic nginx" > /etc/apt/sources.list.d/nginx.list
echo "deb-src http://nginx.org/packages/mainline/ubuntu/ bionic nginx" >> /etc/apt/sources.list.d/nginx.list
Replace bionic
with your version of Ubuntu (use lsb_release -a
to find out).
Install nginx from the newly added repository:
apt-get update;
apt-get install nginx
Configure nginx for ssl preread protocol
Quoted from the nginx blog:
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.
This piece of configuration must go in the root of your nginx config, not inside
a server
block.
stream {
upstream ssh {
server 192.0.2.10:22;
}
upstream https {
server 192.0.2.20:443;
}
map $ssl_preread_protocol $upstream {
default ssh;
"TLSv1.2" https;
"TLSv1.3" https;
"TLSv1.1" https;
"TLSv1.0" https;
}
# SSH and SSL on the same port
server {
listen 443;
proxy_pass $upstream;
ssl_preread on;
}
}
In this case, if the protocol detected is TLSv1.2
, HTTPS is assumed and the
traffix is forwarded to the HTTPS server (192.0.2.20
). Otherwise the traffic is
forwarded to the SSH host (192.0.2.10
).
SSH and HTTPS on the same server
If you want to split ssh
and https
on the same server, the configuration is
a little bit different. You first must make sure that there is no other website
listening on port :443
, because that is what nginx will use for its proxy.
Not even another site withing nginx is allowed to use port 443. Change your listen
blocks to use port 8443
, for example:
listen [::]:8443 http2;
listen 8443 http2;
The configuration for ssh/ssl must not go in a server
directive, but in the
root of your nginx config:
stream {
upstream ssh {
server 127.0.0.1:22;
}
upstream https {
server 127.0.0.1:8443;
}
map $ssl_preread_protocol $upstream {
default ssh;
"TLSv1.2" https;
"TLSv1.3" https;
"TLSv1.1" https;
"TLSv1.0" https;
}
#
# SSH and SSL on the same port
server {
listen 443;
proxy_pass $upstream;
ssl_preread on;
}
}
More fun with ssl_preread
The ssl_preread
module can detect more than the protocol. The SNI server name is also supported, which allows for proxy forwarding to different backend servers based on the requested SSL hostname. Quoting the documentation:
map $ssl_preread_server_name $name {
backend.example.com backend;
default backend2;
}
upstream backend {
server 192.168.0.1:12345;
server 192.168.0.2:12345;
}
upstream backend2 {
server 192.168.0.3:12345;
server 192.168.0.4:12345;
}
server {
listen 12346;
proxy_pass $name;
ssl_preread on;
}
Do note that this also requires a newer version of nginx than by default in the Ubuntu 16.04 or 18.04 release.
Tags: firewall , folder , multiplex , nginx , proxy , security , ssh , sslh , subfolder , tutorials