4 min read

HOWTO connect to SSH via SSL with sslh

Since I’m in the commandline fulltime, SSH is an indispensable tool for ‘getting things done’ - heck, I even run it on my Android phone now so I can poke around there (haven’t broken anything… yet), so when I’m traveling or at a client’s site that doesn’t allow outgoing ssh (port :22) we have a problem. In the past I’ve always mapped SSH to some port other than :22 to prevent drive-by brute forcing login attempts, so I’ve put it on :443 (which is rarely blocked for outgoing is connections), but now that I’m running this site with SSL, that is no longer an option. Yes, we could try out :8080 (Tomcat’s port), :8443 (Tomcat’s SSL port) or :8181 (Debian’s old Tomcat port), but we’ll always have a better chance to get out over :443. While I’ve read how this might be possible using the great HAProxy, that always seemed like overkill and begged for a simplier solution. Apparently there already was one, I had just never heard of it; sslh is an applicative protocol multiplexer, that forward ports initially sent to :443 on to other needed ports. Their description on what it can do:

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.

Sounds perfect, so I went to install and configure it, and it was easier than I expected so let’s get started - first of all I found a schmatic that illustrates what’s happening [source]


The package is already in Debian's Wheezy repo, and likely others, so for me it was simple to get rolling:
apt-get install sslh

Now let’s take a look at how to configure it and get it working. First we’ll want to tell the webserver to listen on 127.0.0.1:443, instead of on all interfaces, 0.0.0.0:443, which it is usually doing by default. I use nginx, so it was a matter of changing the following

listen              443 ssl;

to

listen              127.0.0.1:443 ssl;

Now we’ll then test the nginx config to make sure we don’t have any ttyyppos (it happens)

nginx -t

If all is good, we’ll restart nginx so it’ll start listening on 127.0.0.1 and not 0.0.0.0

/etc/init.d/nginx restart

And then we can verify this with netstat

# netstat -plunt | grep nginx | grep 443
tcp        0      0 127.0.0.1:443           0.0.0.0:*               LISTEN      15261/nginx

Now, if you’re using Apache is a similar deal, in httpd.conf or apache.conf, change

Listen 443

to

Listen 127.0.0.1:443

and if you’re using Virutalhosts in Apache, be sure those configs look like

VirtualHost 127.0.0.1:443

Now make sure you can still hit your https site, “It should work (tm)”, and then we’ll configure sslh. Start with

vi /etc/default/sslh

We need to change two things, first set it so sslh will start, so change

RUN=no

to

RUN=yes

Makes sense, yes? Moving on we need to change the IP that sslh will be listening to for https :443 and ssh :22 connections, so we’ll change this line

DAEMON_OPTS="--user sslh --listen 0.0.0.0:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:443 --pidfile /var/run/sslh/sslh.pid"

To another use another IP, I used the systems local IP (yours will be different)

DAEMON_OPTS="--user sslh --listen 10.10.0.110:443 --ssh 10.10.0.110:22 --ssl 127.0.0.1:443 --pidfile /var/run/sslh/sslh.pid"

Now we should be able to start sslh

/etc/init.d/sslh start

And test it from a remote host, pointing to your IP or Domain on :443

ssh -p 443 luser@${domainname}.${tld}

Did it work? Great! If not, rerun the command with ssh -v to debug the issue.

This opens up a lot of new options, from connecting to a local XMMP/jabber server to a more reliable way to conect home via OpenVPN, but also raises the question of security. I’ll do some tests on that and report back on what is exposed by sshl to the outside when a client hits :443.