{"id":14273,"date":"2017-05-17T05:51:25","date_gmt":"2017-05-17T12:51:25","guid":{"rendered":"http:\/\/ainslies.net\/?p=14273"},"modified":"2022-10-09T06:10:08","modified_gmt":"2022-10-09T13:10:08","slug":"using-letsencrypt-with-stunnel","status":"publish","type":"post","link":"https:\/\/ainslies.net\/?p=14273","title":{"rendered":"Using letsencrypt with stunnel"},"content":{"rendered":"<p>I wanted to use <a href=\"https:\/\/letsencrypt.org\/\">letsencrypt<\/a> keys and stunnel to encrypt sessions with a valid server key.&nbsp;Once setup the system needed to look like a regular https website with a valid certificate. I&#8217;ll explain why I did this in a later posting.<\/p>\n<p>I&#8217;m not going to go into getting the original key from letsencrypt as there are too many ways to do it and letsencrypt&#8217;s certbot is already well documented.<\/p>\n<p>These instructions are also specific to Ubuntu 16.04 but could be modified for other Linux&#8217;s. The instructions below will also conflict with any webserver listening on port 443 (https).<\/p>\n<h2>Setup stunnel<\/h2>\n<p>In all of the instructions and scripts below replace &lt;servername&gt; with your hostname. &lt;servername&gt; also needs to match you letsencrypt hostname.<\/p>\n<pre>sudo apt-get install stunnel4\n<\/pre>\n<p>Edit \/etc\/default\/stunnel4 and change ENABLED=1<\/p>\n<p>Now create a new stunnel conf file in \/etc\/stunnel\/ with the contents below<\/p>\n<pre>pid = \/var\/run\/stunnel.pid\ncert = \/etc\/stunnel\/stunnel.pem\n[ssh]\naccept = &lt;servername&gt;:443\nconnect = 127.0.0.1:80\n<\/pre>\n<p>If you want to connect to something other than you local webserver change the &#8220;connect = 127.0.0.1:80&#8221; line above.<\/p>\n<p>Now because stunnel needs the fullchain.pem and the privkey.pem in the same file we need to combine the letsencrypt files. Here&#8217;s a script ( <a href=\"http:\/\/ainslies.net\/files\/combine_certs.sh\">combine_certs.sh<\/a> ) that will check the md5sums of the letsencrypt file and generate a new stunnel.pem whenever the originals change.<\/p>\n<pre>#!\/bin\/bash\n#\n# Copyright (c) 2017 Angus Ainslie \n#\n\nIN_PATH=\"\/etc\/letsencrypt\/live\"\nCERT_NAME=$1\nOUT_PATH=$2\nPEM_NAME=$3\n\nCHAIN_SUM=`md5sum ${IN_PATH}\/${CERT_NAME}\/fullchain.pem`\nKEY_SUM=`md5sum ${IN_PATH}\/${CERT_NAME}\/privkey.pem`\n\necho \"Chain sum ${CHAIN_SUM}\"\necho \"Key sum ${KEY_SUM}\"\n\nif [ ! -e ${OUT_PATH}\/sums ]; then\n  echo ${CHAIN_SUM} &gt; ${OUT_PATH}\/sums\n  echo ${KEY_SUM} &gt;&gt; ${OUT_PATH}\/sums\nfi\n\nmd5sum --status -c ${OUT_PATH}\/sums\n\nif [ $? -eq 0 ]; then\n  echo \"Keys match\"\nelse\n  echo \"Keys don't match. re-creating pem file\"\n  cat ${IN_PATH}\/${CERT_NAME}\/fullchain.pem ${IN_PATH}\/${CERT_NAME}\/privkey.pem &gt; ${OUT_PATH}\/${PEM_NAME}\n  echo ${CHAIN_SUM} &gt; ${OUT_PATH}\/sums\n  echo ${KEY_SUM} &gt;&gt; ${OUT_PATH}\/sums\nfi\n<\/pre>\n<p>To generate the stunnel.pem file run combine_certs.sh like this<\/p>\n<pre>sudo combine_certs.sh &lt;servername&gt; \/etc\/stunnel stunnel.pem\n<\/pre>\n<p>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 <a href=\"http:\/\/ainslies.net\/files\/check-certs\">crontab<\/a> in \/etc\/cron.d<\/p>\n<pre># Copyright (c) 2017 Angus Ainslie &lt;angus at akkea.ca&gt;\n#\nSHELL=\/bin\/bash\nPATH=\/usr\/local\/sbin:\/usr\/local\/bin:\/sbin:\/bin:\/usr\/sbin:\/usr\/bin\n\n5 *\/12 * * * root test -x \/usr\/local\/bin\/combine_certs.sh &amp;&amp; combine_certs.sh  \/etc\/stunnel stunnel.pem\n<\/pre>\n<p>Now restart stunnel<\/p>\n<pre>systemctl restart stunnel4\n<\/pre>\n<p>You will now have a fully functional stunnel listener that will function as an https server.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wanted to use letsencrypt keys and stunnel to encrypt sessions with a valid server key.&nbsp;Once setup the system needed to look like a regular https website with a valid certificate. I&#8217;ll explain why I did this in a later &hellip; <a href=\"https:\/\/ainslies.net\/?p=14273\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-14273","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/ainslies.net\/index.php?rest_route=\/wp\/v2\/posts\/14273","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ainslies.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ainslies.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ainslies.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ainslies.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=14273"}],"version-history":[{"count":10,"href":"https:\/\/ainslies.net\/index.php?rest_route=\/wp\/v2\/posts\/14273\/revisions"}],"predecessor-version":[{"id":14356,"href":"https:\/\/ainslies.net\/index.php?rest_route=\/wp\/v2\/posts\/14273\/revisions\/14356"}],"wp:attachment":[{"href":"https:\/\/ainslies.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=14273"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ainslies.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=14273"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ainslies.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=14273"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}