Socat, sslh and stunnel to share https port 443

The instructions below assume you are using Ubuntu 16.04 but they will work for other Linuxes with minor modifications. The instructions below will also conflict with a webserver listening on port 443 ( https ) so you’ll need to disable it. Once the setup below is complete your https connections will get seamlessly forwarded to port 80.

Setup letsencrypt keys

For the SSL connection to be secure and trusted by browsers and other software you need to have a certificate signed by a recognised certificate authority. The easiest way to do this is to use letsencypt’s certbot. I’m not going to go into how to get the certificate as there are too many ways depending on your configuration. Just follow letsencrypt’s documentation to generate a key for your "" that will get used in the rest of these instructions.

You could also use a self signed key but that may cause you problems with stateful firewalls.

Setup stunnel

With your certificate installed on the server you can now setup stunnel to use it. crow shows a partial setup here. I think he’s limited the ciphers for increased security but I found it was not necessary.

Install stunnel4

sudo apt-get install stunnel4

So the setup in /etc/stunnel/stunnel.conf I am using looks like this

pid = /var/run/
cert = /etc/letsencrypt/live/
key = /etc/letsencrypt/live/
accept =
connect = localhost:80

You also need to enable stunnel in /etc/default/stunnel4.conf by setting ENABLED=1

restart stunnel to use the new configuration.

systemctl restart stunnel4

At this point you can test the stunnel setup by going to “” with your browser and you will have a secure connection to your http server.

To prep for the sslh configuration change

connect = localhost:80

in /etc/stunnel/stunnel.conf to

connect = localhost:1022

and then restart stunnel again.

Setup sslh

sslh will redirect the sessions decrypted by stunnel to the correct port on your server.

You need to install sslh

sudo apt-get install sslh

The minimum services I wanted are ssh and http so my configuration in /etc/default/sslh looks like this.


# binary to use: forked (sslh) or single-thread (sslh-select) version

DAEMON_OPTS="--user sslh --listen --http --ssh --pidfile /var/run/sslh/"

The sslh documentation says that OpenVPN, tinc, XMPP are also supported but I didn’t need those so my configuration doesn’t support them. You can now restart sslh

sudo systemctl restart sslh

This would be another good time to test the stunnel -> sslh -> httpd redirection by visiting “” in your browser.

Client side ssh setup

Once all of the above is complete and assuming that you have an ssh server that you can connect to on port 22 of your server the ssh client can be setup to use the ssl tunnel. The ssh session needs to wrapped in the ssl session to be able to connect to the server so I used the ssh ProxyCommand to accomplish this. Add the section below to your ~/.ssh/config on your client machine

ProxyCommand /usr/bin/socat -

From the client you should now be able to connect to your server by doing


If you get errors from ProxyCommand about your keys or if you used a self signed certificate you will need to turn off key verification.

ProxyCommand /usr/bin/socat -,verify=0

There is usually one other modification I have in my ssh config and that is a DynamicProxy so that stateful packet inspection doesn’t interfere. So the final configuration looks like this.

DynamicForward localhost:2121
ProxyCommand /usr/bin/socat -

The interested reader should look into FoxyProxy to see how this might be used.

Using letsencrypt with stunnel

I wanted to use letsencrypt keys and stunnel to encrypt sessions with a valid server key. Once setup the system needed to look like a regular https website with a valid certificate. I’ll explain why I did this in a later posting.

I’m not going to go into getting the original key from letsencrypt as there are too many ways to do it and letsencrypt’s certbot is already well documented.

These instructions are also specific to Ubuntu 16.04 but could be modified for other Linux’s. The instructions below will also conflict with any webserver listening on port 443 (https).

Setup stunnel

In all of the instructions and scripts below replace <servername> with your hostname. <servername> also needs to match you letsencrypt hostname.

sudo apt-get install stunnel4

Edit /etc/default/stunnel4 and change ENABLED=1

Now create a new stunnel conf file in /etc/stunnel/ with the contents below

pid = /var/run/
cert = /etc/stunnel/stunnel.pem
accept = <servername>:443
connect =

If you want to connect to something other than you local webserver change the “connect =” line above.

Now because stunnel needs the fullchain.pem and the privkey.pem in the same file we need to combine the letsencrypt files. Here’s a script ( ) that will check the md5sums of the letsencrypt file and generate a new stunnel.pem whenever the originals change.

# Copyright (c) 2017 Angus Ainslie 


CHAIN_SUM=`md5sum ${IN_PATH}/${CERT_NAME}/fullchain.pem`
KEY_SUM=`md5sum ${IN_PATH}/${CERT_NAME}/privkey.pem`

echo "Chain sum ${CHAIN_SUM}"
echo "Key sum ${KEY_SUM}"

if [ ! -e ${OUT_PATH}/sums ]; then
  echo ${CHAIN_SUM} > ${OUT_PATH}/sums
  echo ${KEY_SUM} >> ${OUT_PATH}/sums

md5sum --status -c ${OUT_PATH}/sums

if [ $? -eq 0 ]; then
  echo "Keys match"
  echo "Keys don't match. re-creating pem file"
  cat ${IN_PATH}/${CERT_NAME}/fullchain.pem ${IN_PATH}/${CERT_NAME}/privkey.pem > ${OUT_PATH}/${PEM_NAME}
  echo ${CHAIN_SUM} > ${OUT_PATH}/sums
  echo ${KEY_SUM} >> ${OUT_PATH}/sums

To generate the stunnel.pem file run like this

sudo <servername> /etc/stunnel stunnel.pem

Because the letsencrypt certificates are short lived their install process adds a cron job that will renew any keys expiring in 30 days or less. So we need to rerun the combine script to keep our stunnel.pem current. Put this crontab in /etc/cron.d

# Copyright (c) 2017 Angus Ainslie <angus at>

5 */12 * * * root test -x /usr/local/bin/ &&  /etc/stunnel stunnel.pem

Now restart stunnel

systemctl restart stunnel4

You will now have a fully functional stunnel listener that will function as an https server.