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]
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.