Use case
Sometimes when I'm behind a corporate firewall I want to get my connection secure and private against any traffic inspection. The quickest way is by using SSH as SOCKS5 proxy or a VPN but the firewall blocks my SSH and VPN ports! After a quick scan, the open ports are 53, 80 and 443. Ah ha! that's it, just change my SSH or VPN port to 443 since that port is common and less suspicious but you can't just changing the SSH/VPN port to 443 as you have a website running through that port. So this is where sslh comes in handy.
Introduction
sslh is a program that allows you to run sereval programs on port 443. Mainly it allows SSH server and web server to share same port.
sslh accepts connections on specified ports(443) and forwards them further based on test performed on the first data packet sent by the remote client.
It probes for HTTP, SSL, SSH, OpenVPN, tinc, XMPP are implemented, and any other protocol that can be tested using a regular expression, can be recognised. A typical use case is to allow serving several services on port 443 (e.g. to connect to SSH from inside a corporate firewall, which almost never block port 443) while still serving HTTPS on that port.
Hence sslh acts as a protocol demultiplexer, or a switchboard. Its name comes from its original function to serve SSH and HTTPS on the same port.
source: github.com
This guide will show you how to install and setup sslh to use SSH, OpenVPN, and HTTPS webserver running on the same port.
Prerequisites
Before following this guide, I assume you already have Nginx webserver with HTTPS, OpenSSH, and OpenVPN installed.
Install
Install sslh
in your server via apt install
. In my opinion, the best is to install from package distribution not to compile from source as installing from apt
can keep track of the package, easy to uninstall and upgrade the package.
sudo apt install sslh
When it ask you how sslh to be run, choose standalone
.
Configure
There's not much to configure. I keep the same port 22 on SSH so that I can connect SSH normally via port 22 and 443 via sslh, and OpenVPN on 8080/TCP. Important to make sure your OpenVPN on any TCP port not UDP. The things to change is the SSL listener port on Nginx.
Change OpenVPN to listen to TCP
If your OpenVPN already listen to TCP port, skip this. Open /etc/openvpn/server.conf
sudo nano /etc/openvpn/server.conf
Change your port to something else and proto TCP
# Which TCP/UDP port should OpenVPN listen on?
# If you want to run multiple OpenVPN instances
# on the same machine, use a different port
# number for each one. You will need to
# open up this port on your firewall.
port 1194
# TCP or UDP server?
proto tcp
;proto udp
Save and close.
Changing Nginx SSL listener port
Find somewhere on your nginx config files that listen to port 443 for SSL and change that to something else like 4433.
# usually:
listen 443 ssl;
# change that to:
listen 127.0.0.1:4433 ssl;
We make nginx to listen to localhost on port 4433. By using sslh we will redirect https port 443 to nginx 4433.
Configure SSLH
Once you have made the webservers to listen on local interface only, edit SSLH bashconfig file:
sudo nano /etc/default/sslh
find the following line:
Run=no
and change it to:
Run=yes
Then, scroll a little bit down and modify the following line to allow SSLH to listen on port 443 on all available interfaces (Eg. 0.0.0.0:443).
DAEMON_OPTS="--user sslh --listen 0.0.0.0:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:4433 --openvpn 127.0.0.1:1194 --pidfile /var/run/sslh/sslh.pid --timeout 5"
Where,
--user sslh
: Requires to run under this specified username.
--listen 0.0.0.0:443
: SSLH is listening on port 443 on all available interfaces.
--ssh 127.0.0.1:22
: Route SSH traffic to port 22 on the localhost.
--ssl 127.0.0.1:4433
: Route HTTPS/SSL traffic to port 4433 on the localhost.
--openvpn 127.0.0.1:1194
: Route OpenVPN traffic to port 1194 on the localhost.
--timeout 5
: Give sslh a timeout for 5sec. To be use when your OpenVPN connect to HTTP proxy.
Save and close the file.
Finally, enable and start sslh service to update the changes.
sudo systemctl enable sslh
sudo service sslh start
sudo service openvpn restart
sudo service sshd restart
sudo service nginx restart
Testing
Check if the sslh daemon is running and listening to 443. Your output is probably same like me.
ps -ef | grep sslh
sslh 1187 1 0 Jan01 ? 00:00:00 /usr/sbin/sslh --foreground --user sslh --listen 0.0.0.0 443 --ssh 127.0.0.1 22 --openvpn 127.0.0.1 1194 --ssl 127.0.0.1 4433 --pidfile /var/run/sslh/sslh.pid --timeout 5
sslh 1188 1187 0 Jan01 ? 00:00:00 /usr/sbin/sslh --foreground --user sslh --listen 0.0.0.0 443 --ssh 127.0.0.1 22 --openvpn 127.0.0.1 1194 --ssl 127.0.0.1 4433 --pidfile /var/run/sslh/sslh.pid --timeout 5
sslh 29544 1188 0 16:40 ? 00:00:00 /usr/sbin/sslh --foreground --user sslh --listen 0.0.0.0 443 --ssh 127.0.0.1 22 --openvpn 127.0.0.1 1194 --ssl 127.0.0.1 4433 --pidfile /var/run/sslh/sslh.pid --timeout 5
user 29599 29586 0 16:41 pts/0 00:00:00 grep --color=auto sslh
Check your webserver
Open your browser and try to browse to your website over https.
Connect to SSH to port 443
Try connect SSH to your VPS from port 443:
ssh -p 443 [email protected]
Now, you can access your remote server via SSH using port 443. You may want to use the SSH connection as SOCKS5 proxy. Check it out here.
Connect OpenVPN
Edit the protocol and remote address port in your client.ovpn
file.
# Are we connecting to a TCP or
# UDP server? Use the same setting as
# on the server.
proto tcp
;proto udp
# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
remote {your_vpn_server_ip} 443
Save and close the file. Try to connect to VPN:
sudo openvpn --config client.ovpn
Conclusion
See? I can now be able to access the remote server via SSH even if the default SSH port 22 is blocked. As you see in the above example, I have used the https port 443 for SSH connection and OpenVPN. For more details, check the project’s website URL given below.
Cheers!
Reference: http://www.rutschle.net/tech/sslh.shtml
Github: https://github.com/yrutschle/sslh