0%
False
Go Back

Basic guide to configuration of SSLH

Setting up an IPv4/IPv6 dual stack server with support for both HTTPS and SSH on a single port.

Posted by Zain Ahmed on February 22, 2024

Introduction

This is somewhat of a follow up to an older blog post, regarding how to bypass firewalls and other restrictions via SSH. Sometimes you may not have access to the traditional port 22, and in some cases to not any ports aside from either 443 or 80.
Now if you ended up in the latter situation, like I did, then it would be very troublesome without some sort of solution such as Cloudflare. But you may for various reasons desire a direct webserver without any sort of CDN or the likes sitting infront of it. And that is where SSLH comes in!

What is SSLH?

As mentioned in the previous post, SSLH is a multiplexer that allows you to run SSH, HTTPS, and even OpenVPN across a single port. In this post we will only go over configuring SSLH to forward HTTPS (specifcally with NGINX but this can be applied to other webserver) and SSH traffic over port 443.

SSLH can simply be installed on any debian system through apt, by running apt install sslh. This now leads us to the configuration!

Configuring SSLH

This is the tricky part. I am going to go over how to configure the server to support connections over both IPv4 and IPv6, if you would like to configure either one, then you'll need to pay attention to only the bits where I go over the version you desire to setup.

First things first, we need to locate our SSLH configuration. On my machine, by default it is located at /etc/default/sslh, but this may vary on your own system.
Normally we could just put the IP addresses directly into the configuration and call it a day, but since I am setting up a dual stack (IPv4/IPv6) system, that requires slightly more configuration.

To ensure dual stack operation, we must first edit our hosts file, located at /etc/hosts. We are going to need two sets of IP addresses, you can do this with a single IP but that is too much complexity to cover this post. If you are running on a server that has only a single public IP address you may swap the second address for localhost, or some other private address, but in this case as I am behind NAT for IPv4 with a /64 for IPv6, I am just going to use two separate addresses.
Configure the "External" IP address first. This is the IP that SSLH will listen to traffic coming into the server. In my case I am using 192.168.1.235 as the external IP for IPv4, and for IPv6 I am using 2001:470:b831::c. As for my Internal address, I am using 2001:470:b831::d for IPv6 and 192.168.1.216 for IPv4. The "Internal" address is the IP on which we are configuring NGINX to listen to. SSH can continue to use your regular/external IP address.
To add entries to the host file, simply put the IP address, followed by a space, and then the desired hostname. As an example, the hostname for my External IP will simply be external, so the entry would look like 192.168.1.235. Add the entry for both your Internal and External addresses (if going dual stack then put one each for IPv6 and IPv4), and save the file.

Now for actually setting up SSLH. Refer back to that configuration file we looked at earlier. There should be a line starting with DAEMON_OPTS=. This is the line we need to mess with.
I have mine configured like such: DAEMON_OPTS="--user sslh --transparent --listen internal:443 --tls external:443 --ssh internal:22".
You can modify the bits as you need. --tls configures where to forward tls traffic to, in this case we are going to forward it to where we are making Nginx bind to. --ssh is self explanatory, it is a directive as to where to forward SSH traffic, in this case I am not going to bother reconfiguring SSH, so we'll just have it go to the IP that I was already using (which I am calling Internal in this case). --transparent is pretty important, as this allows for SSLH to show the information of the client, such as the client's own IP address, instead of the server that SSLH is running on. (and yes, SSLH can forward to other servers should you wish to configure it to do so).
Now we can save this file and move on to confiuring Nginx.

Configuring Nginx

The Nginx configuration is also pretty straight forward, albeit can be tedious. By default Nginx will want to bind to 0.0.0.0 and :: (the IPv6 version of 0.0.0.0). This is undesirable as we would like SSLH to bind to Port 443 on a certain IP, which would result in a conflict if we left the default behaviour.
Simply add these two directives to every server block in your configuration. It must be all server blocks configured, if you know of a way to just configure Nginx globally to listen on a specific IP address then please let me know.
listen <EXTERNAL_IPV4_HERE>:443 ssl http2;
listen [<EXTERNAL_IPV6_HERE>]:443 http2;
In my case it looks like so:
listen 192.168.1.235:443 ssl http2;
listen [2001:470:b831::d]:443 http2;
Ensure that there are no other listen directives in the server blocks.
If you are using any other server that is not Nginx, similarly configure it to listen to those IP addresses. With the --transparent flag in the SSLH configuration, it should be seamless, and your webserver should recieve the client IP address and all other information, as if there was nothing in-between.
We can now setup an HTTPS redirect, forcing all HTTP connections over port 80 to be redirected to HTTPS over 443. Simply add the following to your configuration:

server {
       listen         80 default_server;
       listen         [::]:80 default_server;
       server_name    $host;
       return         301 https://$host$request_uri;
    }
This will be running on 0.0.0.0:80 and [::]:80 (all IPs bound to the machine), but you can modify this to your liking.

Configuring IPTables

Due to certain issues (that honestly I'm not too sure about either), we will also need to do some configuration with SSLH. This will be needed each time the server boots up. But never fear! For shell scripts are here!
I have provided a shell script here, which you can view to your own liking. Simply add this shell script to somewhere on your own machine, run chmod +x sslh-iptables.sh to make it executable and then run the script. You can also optionally setup a cron job to fire at boot unless you wish to run the script at each reboot manually (or perhaps integrate it into something else).
On my machine it looks like @reboot sh /home/zain/sslh-iptables.sh.
Now all should be setup and all you need to do is reload nginx (nginx -s reload), and start up SSLH.
You can test the configuration by simply attempting to SSH over port 443 or accessing Nginx, both should be working.

Conclusion

Hopefully you found this guide useful! I have had alot of friends ask me how to setup SSLH so I just put a guide here for anyone (not just my friends) to find in the event they get confused. If there is anything that doesn't work here or is outdated, I apologise as I am not able to always keep up with everything. You may however contact me by leaving a message here at any time!