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/stunnel.pid
cert = /etc/stunnel/stunnel.pem
[ssh]
accept = <servername>:443
connect = 127.0.0.1:80

If you want to connect to something other than you local webserver change the “connect = 127.0.0.1:80” 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 ( combine_certs.sh ) that will check the md5sums of the letsencrypt file and generate a new stunnel.pem whenever the originals change.

#!/bin/bash
#
# Copyright (c) 2017 Angus Ainslie 
#

IN_PATH="/etc/letsencrypt/live"
CERT_NAME=$1
OUT_PATH=$2
PEM_NAME=$3

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
fi

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

if [ $? -eq 0 ]; then
  echo "Keys match"
else
  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
fi

To generate the stunnel.pem file run combine_certs.sh like this

sudo combine_certs.sh <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 akkea.ca>
#
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

5 */12 * * * root test -x /usr/local/bin/combine_certs.sh && combine_certs.sh  /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.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.