From f6358543fb47bd002370deb71ca8660e78663deb Mon Sep 17 00:00:00 2001
From: Bob Mottram <bob@robotics.uk.to>
Date: Tue, 17 Nov 2015 22:21:40 +0000
Subject: [PATCH] More preparation for letsencrypt

---
 man/freedombone-addcert.1.gz | Bin 580 -> 639 bytes
 src/freedombone              | 157 +++++++++++++++++++++--------------
 src/freedombone-addcert      | 135 +++++++++++++++++++++++-------
 src/freedombone-controlpanel |  34 +++++++-
 src/freedombone-renew-cert   |  30 +++++--
 src/freedombone-sec          |   2 +-
 6 files changed, 255 insertions(+), 103 deletions(-)

diff --git a/man/freedombone-addcert.1.gz b/man/freedombone-addcert.1.gz
index 1fb9de8655b7251b0a510d8d1240d9e54c34f0ab..3efbd4111182cbe442998c8f290cd2c0ecd93d99 100644
GIT binary patch
literal 639
zcmV-_0)YJ=iwFP@L`zlx1ASB5Zqq;zefL+4{8EsxLy8b3LWradN!8pGCsYvnuwIYt
zRqb7CXC27jGfoq=QCuuP*mF5^&e_>;HHOq8CZ>#y#y}*AMC+gne)kj1%oZ-+cR%{z
z^ZWg|4%USBf?z6iEehZB!e|WstUn$4UK`x+0Qx}Es>(rXEJ%yODV;%qj!;Xx;{?YE
zi!>mWX-uGLRH>4}A%W3wgRv6&Fe>^vn=hi<sC`_3u*nTMElPZVAV2vd*i3jT3=d;j
z$rdfFmlIA(*ho`rXLle?(v%C>2xiM)1#Ak#bd=HjXJBJ&CbXhsq=rqcmE*4<$scjY
z<)|~4gVGQyM@>STgxNS-V<!~_;ln}C%`m!N-Y!<R^O^5mH}0@#R4!*`0+{c`Ghx$&
zUU6#gE_Xquwy5DKJ3Ne8NBt2W(P~$5bpbVr?5X8-Kt(;z1AbbKerc`e&Ful~l<*6<
z|6$=NR@K-lied*lQ-c&5*f0ZBp;YM(xJ^A(KqV~qIJ9)sIarT)HI`Tz29E2DKsYZP
zK<->cy-p`%XX`kWrtHLmaw|J87<Cj;jda|!;Sl<hXnwM3Z@O>aorsWyLhTwIXDKF%
zrBFp%qEOV@@VBh0S7w}tjZRf|7Uq*Q_MB*C@f_J=Y210OMU8)gR#CQW*JR69Nw#cN
zL@3W<e1+PXHwZx`h&XdNoBnz=o-ciGU}BgW=Xed^OKjqA*2KmsNn!mMI`h>FW9uzO
zi_T~<>cO!8`Ra1`;c6cpC|4pi_n-%ZX>cj;>%1Ine<Z0L=M(d5l~8s4c!z3b>>4SW
Z?7QwU?(LU}cj<JN_YW3<^VL!X002+9Fp2;G

literal 580
zcmV-K0=xYmiwFRc^UhTO1BFsiZ__{we!pK~<pq#PLN_6e3L)C9v=i%EEiDMj9xfLr
zIW0Ly=gXk~o=a&3Q!)|dA+bMy{yy8$W&ycH%&1PuU?{Upp>;5V;Cuv2Y2ob6=xqRj
ze?R@j!Isg!U=J{@tO6mTWC6kLWH}4O5Z#XuCcw(-#z9UNltt;ZDS)xcL)L}C3_7IF
zwUQ1Q$iNk*TACww^6hrDPOg(-{;-5yN$iZQ@g712J4LN=b`OfOE+SzkeNX>Y!LB0T
zLzD4;1Us^YG@4J57Iv-C&VPkj`G9*5M^m^Gw1HGR?h=MF-_Y3><6KsZ_eYUev*hyb
zdcC<`-3H>a^XQ$(=S&_Z;Yx%;Kcaz?{^&@yO(t_c&dt8@=n7hv1%l?W5a6HxPC<xO
z(^-;LwTC^mpripWmVg^nI^TmY(|-`qNb74HT0V83Zs&g1ci508PTRu!a3Y#Q>0HC(
zI4-m++cZ*C$EoDfs`wv8v1V?OPpg~FU~-eJo~-WW=+)~dCRC--xXwo}<%MD`bv2Zz
zG!GX1s+;DS9{n(xTo=8tUl`fG(8gk)*<wwukF{v<XE<oe*2A7`J!r|+gN_(gFXqp8
zSb4_~Hj>$Aj=Py`H;dI>Af}YUlAQBr0Pj;uKUzx3X~j|d5IOoFqST7@d>zl%^D)dO
z?=H?}=NE_QRJ$6vyUsC8m*JWE+Lrb7@k^H5MR`NtHyJmV51&zQ$ZnC7n?u!COvi^~
S^0)M~m-r1bq1v021ONb%KPI36

diff --git a/src/freedombone b/src/freedombone
index 60fe84c75..465daadf7 100755
--- a/src/freedombone
+++ b/src/freedombone
@@ -429,6 +429,9 @@ DH_KEYLENGTH=2048
 # repo for atheros AR9271 wifi driver
 ATHEROS_WIFI_REPO='https://github.com/qca/open-ath9k-htc-firmware.git'
 
+LETSENCRYPT_ENABLED="no"
+LETSENCRYPT_SERVER='https://acme-v01.api.letsencrypt.org/directory'
+
 function show_help {
   echo ''
   echo 'freedombone -c [configuration file]'
@@ -788,6 +791,9 @@ function read_configuration {
   fi
 
   if [ -f $CONFIGURATION_FILE ]; then
+      if grep -q "LETSENCRYPT_SERVER" $CONFIGURATION_FILE; then
+          LETSENCRYPT_SERVER=$(grep "LETSENCRYPT_SERVER" $CONFIGURATION_FILE | awk -F '=' '{print $2}')
+      fi
       if grep -q "HUBZILLA_COMMIT" $CONFIGURATION_FILE; then
           HUBZILLA_COMMIT=$(grep "HUBZILLA_COMMIT" $CONFIGURATION_FILE | awk -F '=' '{print $2}')
       fi
@@ -1185,13 +1191,24 @@ function check_certificates {
   if [ ! $1 ]; then
       return
   fi
-  if [ ! -f /etc/ssl/private/$1.key ]; then
-      echo "Private certificate for $CHECK_HOSTNAME was not created"
-      exit 63959
-  fi
-  if [ ! -f /etc/ssl/certs/$1.crt ]; then
-      echo "Public certificate for $CHECK_HOSTNAME was not created"
-      exit 7679
+  if [[ $LETSENCRYPT_ENABLED != "yes" ]]; then
+      if [ ! -f /etc/ssl/private/$1.key ]; then
+          echo "Private certificate for $CHECK_HOSTNAME was not created"
+          exit 63959
+      fi
+      if [ ! -f /etc/ssl/certs/$1.crt ]; then
+          echo "Public certificate for $CHECK_HOSTNAME was not created"
+          exit 7679
+      fi
+  else
+      if [ ! -f /etc/letsencrypt/live/${1}/privkey.pem ]; then
+          echo "Private certificate for $CHECK_HOSTNAME was not created"
+          exit 6282
+      fi
+      if [ ! -f /etc/letsencrypt/live/${1}/fullchain.pem ]; then
+          echo "Public certificate for $CHECK_HOSTNAME was not created"
+          exit 5328
+      fi
   fi
   if [ ! -f /etc/ssl/certs/$1.dhparam ]; then
       echo "Diffie–Hellman parameters for $CHECK_HOSTNAME were not created"
@@ -3072,9 +3089,14 @@ function restore_database {
   echo '            rm -rf $USB_MOUNT' >> $script_name
   echo '            exit 683' >> $script_name
   echo '          fi' >> $script_name
-  echo '          # Ensure that the bundled SSL cert is being used' >> $script_name
-  echo '          if [ -f /etc/ssl/certs/${2}.bundle.crt ]; then' >> $script_name
-  echo '            sed -i "s|${2}.crt|${2}.bundle.crt|g" /etc/nginx/sites-available/${2}' >> $script_name
+  echo '          if [ -d /etc/letsencrypt/live/${2} ]; then' >> $script_name
+  echo '            ln -s /etc/letsencrypt/live/${2}/privkey.pem /etc/ssl/private/${2}.key' >> $script_name
+  echo '            ln -s /etc/letsencrypt/live/${2}/fullchain.pem /etc/ssl/certs/${2}.pem' >> $script_name
+  echo '          else' >> $script_name
+  echo '            # Ensure that the bundled SSL cert is being used' >> $script_name
+  echo '            if [ -f /etc/ssl/certs/${2}.bundle.crt ]; then' >> $script_name
+  echo '              sed -i "s|${2}.crt|${2}.bundle.crt|g" /etc/nginx/sites-available/${2}' >> $script_name
+  echo '            fi' >> $script_name
   echo '          fi' >> $script_name
   echo '        fi' >> $script_name
   echo '      fi' >> $script_name
@@ -3698,6 +3720,10 @@ function create_restore_script {
   echo "  if [ -f /etc/ssl/certs/$WIKI_DOMAIN_NAME.bundle.crt ]; then" >> /usr/bin/$RESTORE_SCRIPT_NAME
   echo "    sed -i 's|$WIKI_DOMAIN_NAME.crt|$WIKI_DOMAIN_NAME.bundle.crt|g' /etc/nginx/sites-available/$WIKI_DOMAIN_NAME" >> /usr/bin/$RESTORE_SCRIPT_NAME
   echo '  fi' >> /usr/bin/$RESTORE_SCRIPT_NAME
+  echo "  if [ -d /etc/letsencrypt/live/${WIKI_DOMAIN_NAME} ]; then" >> /usr/bin/$RESTORE_SCRIPT_NAME
+  echo "      ln -s /etc/letsencrypt/live/${WIKI_DOMAIN_NAME}/privkey.pem /etc/ssl/private/${WIKI_DOMAIN_NAME}.key" >> /usr/bin/$RESTORE_SCRIPT_NAME
+  echo "      ln -s /etc/letsencrypt/live/${WIKI_DOMAIN_NAME}/fullchain.pem /etc/ssl/certs/${WIKI_DOMAIN_NAME}.pem" >> /usr/bin/$RESTORE_SCRIPT_NAME
+  echo '  fi' >> /usr/bin/$RESTORE_SCRIPT_NAME
   echo 'fi' >> /usr/bin/$RESTORE_SCRIPT_NAME
   echo '' >> /usr/bin/$RESTORE_SCRIPT_NAME
 
@@ -3739,7 +3765,10 @@ function create_restore_script {
   echo '      fi' >> /usr/bin/$RESTORE_SCRIPT_NAME
   echo '    fi' >> /usr/bin/$RESTORE_SCRIPT_NAME
   echo '  done' >> /usr/bin/$RESTORE_SCRIPT_NAME
-
+  echo "  if [ -d /etc/letsencrypt/live/${FULLBLOG_DOMAIN_NAME} ]; then" >> /usr/bin/$RESTORE_SCRIPT_NAME
+  echo "      ln -s /etc/letsencrypt/live/${FULLBLOG_DOMAIN_NAME}/privkey.pem /etc/ssl/private/${FULLBLOG_DOMAIN_NAME}.key" >> /usr/bin/$RESTORE_SCRIPT_NAME
+  echo "      ln -s /etc/letsencrypt/live/${FULLBLOG_DOMAIN_NAME}/fullchain.pem /etc/ssl/certs/${FULLBLOG_DOMAIN_NAME}.pem" >> /usr/bin/$RESTORE_SCRIPT_NAME
+  echo '  fi' >> /usr/bin/$RESTORE_SCRIPT_NAME  
   echo 'fi' >> /usr/bin/$RESTORE_SCRIPT_NAME
   echo '' >> /usr/bin/$RESTORE_SCRIPT_NAME
 
@@ -4822,9 +4851,14 @@ function restore_database_from_friend {
   echo '          if [ ! "$?" = "0" ]; then' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo '            exit 683' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo '          fi' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
-  echo '          # Ensure that the bundled SSL cert is being used' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
-  echo '          if [ -f /etc/ssl/certs/${2}.bundle.crt ]; then' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
-  echo '            sed -i "s|${2}.crt|${2}.bundle.crt|g" /etc/nginx/sites-available/${2}' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo '          if [ -d /etc/letsencrypt/live/${2} ]; then' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo '              ln -s /etc/letsencrypt/live/${2}/privkey.pem /etc/ssl/private/${2}.key' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo '              ln -s /etc/letsencrypt/live/${2}/fullchain.pem /etc/ssl/certs/${2}.pem' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo '          else' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME  
+  echo '              # Ensure that the bundled SSL cert is being used' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo '              if [ -f /etc/ssl/certs/${2}.bundle.crt ]; then' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo '                  sed -i "s|${2}.crt|${2}.bundle.crt|g" /etc/nginx/sites-available/${2}' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo '              fi' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo '          fi' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo '        fi' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo '      fi' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
@@ -5402,6 +5436,10 @@ function restore_from_friend {
   echo "  if [ -f /etc/ssl/certs/$WIKI_DOMAIN_NAME.bundle.crt ]; then" >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo "    sed -i 's|$WIKI_DOMAIN_NAME.crt|$WIKI_DOMAIN_NAME.bundle.crt|g' /etc/nginx/sites-available/$WIKI_DOMAIN_NAME" >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo '  fi' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo "  if [ -d /etc/letsencrypt/live/${WIKI_DOMAIN_NAME} ]; then" >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo "      ln -s /etc/letsencrypt/live/${WIKI_DOMAIN_NAME}/privkey.pem /etc/ssl/private/${WIKI_DOMAIN_NAME}.key" >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo "      ln -s /etc/letsencrypt/live/${WIKI_DOMAIN_NAME}/fullchain.pem /etc/ssl/certs/${WIKI_DOMAIN_NAME}.pem" >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo '  fi' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo 'fi' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo '' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
 
@@ -5440,6 +5478,10 @@ function restore_from_friend {
   echo '/$USERNAME/blog/uncategorized/post ' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo '    fi' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo '  done' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo "  if [ -d /etc/letsencrypt/live/${FULLBLOG_DOMAIN_NAME} ]; then" >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo "      ln -s /etc/letsencrypt/live/${FULLBLOG_DOMAIN_NAME}/privkey.pem /etc/ssl/private/${FULLBLOG_DOMAIN_NAME}.key" >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo "      ln -s /etc/letsencrypt/live/${FULLBLOG_DOMAIN_NAME}/fullchain.pem /etc/ssl/certs/${FULLBLOG_DOMAIN_NAME}.pem" >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
+  echo '  fi' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo 'fi' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
   echo '' >> /usr/bin/$RESTORE_FROM_FRIEND_SCRIPT_NAME
 
@@ -7128,7 +7170,11 @@ function configure_imap_client_certs {
   fi
   # make a CA cert
   if [ ! -f /etc/ssl/private/ca-$DEFAULT_DOMAIN_NAME.key ]; then
-      freedombone-addcert -h $DEFAULT_DOMAIN_NAME --ca "" --dhkey $DH_KEYLENGTH
+      if [[ $LETSENCRYPT_ENABLED != "yes" ]]; then
+          freedombone-addcert -h $DEFAULT_DOMAIN_NAME --ca "" --dhkey $DH_KEYLENGTH
+      else
+          freedombone-addcert -e $DEFAULT_DOMAIN_NAME -s $LETSENCRYPT_SERVER --dhkey $DH_KEYLENGTH
+      fi
   fi
   # CA configuration
   echo '[ ca ]' > /etc/ssl/dovecot-ca.cnf
@@ -8142,44 +8188,6 @@ function install_web_server {
   echo 'install_web_server' >> $COMPLETION_FILE
 }
 
-function install_letsencrypt {
-  if [[ $SYSTEM_TYPE == "$VARIANT_CHAT" || $SYSTEM_TYPE == "$VARIANT_MESH" ]]; then
-      return
-  fi
-  if grep -Fxq "install_letsencrypt" $COMPLETION_FILE; then
-      return
-  fi
-  #apt-get -y install python-pip git
-  #pip install -U setuptools
-  #pip install --upgrade cffi
-  cd $INSTALL_DIR
-
-  # This is experimental developer preview and I hope at some stage
-  # there will be a debian package for it.
-
-  # obtain the repo
-  if [ ! -d $INSTALL_DIR/letsencrypt ]; then
-      git clone https://github.com/letsencrypt/letsencrypt
-      if [ ! -d $INSTALL_DIR/letsencrypt ]; then
-          exit 76283
-      fi
-  else
-      cd $INSTALL_DIR/letsencrypt
-      git stash
-      git pull
-  fi
-
-  cd $INSTALL_DIR/letsencrypt
-  # TODO this requires user interaction - is there a non-interactive mode?
-  ./letsencrypt-auto --agree-dev-preview --server https://acme-v01.api.letsencrypt.org/directory certonly
-  if [ ! "$?" = "0" ]; then
-      echo 'Failed to install letsencrypt'
-      exit 63216
-  fi
-
-  echo 'install_letsencrypt' >> $COMPLETION_FILE
-}
-
 function configure_php {
   sed -i "s/memory_limit = 128M/memory_limit = ${MAX_PHP_MEMORY}M/g" /etc/php5/fpm/php.ini
   sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g' /etc/php5/fpm/php.ini
@@ -8591,7 +8599,11 @@ quit" > $INSTALL_DIR/batch.sql
   configure_php
 
   if [ ! -f /etc/ssl/certs/$OWNCLOUD_DOMAIN_NAME.dhparam ]; then
-      freedombone-addcert -h $OWNCLOUD_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      if [[ $LETSENCRYPT_ENABLED != "yes" ]]; then
+          freedombone-addcert -h $OWNCLOUD_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      else
+          freedombone-addcert -e $OWNCLOUD_DOMAIN_NAME -s $LETSENCRYPT_SERVER --dhkey $DH_KEYLENGTH
+      fi
       check_certificates $OWNCLOUD_DOMAIN_NAME
   fi
 
@@ -8840,7 +8852,11 @@ quit" > $INSTALL_DIR/batch.sql
   configure_php
 
   if [ ! -f /etc/ssl/certs/$GIT_DOMAIN_NAME.dhparam ]; then
-      freedombone-addcert -h $GIT_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      if [[ $LETSENCRYPT_ENABLED != "yes" ]]; then
+          freedombone-addcert -h $GIT_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      else
+          freedombone-addcert -e $GIT_DOMAIN_NAME -s $LETSENCRYPT_SERVER --dhkey $DH_KEYLENGTH
+      fi
       check_certificates $GIT_DOMAIN_NAME
   fi
 
@@ -9298,7 +9314,11 @@ function install_wiki {
       rm -rf /var/www/$WIKI_DOMAIN_NAME/htdocs
   fi
   if [ ! -f /etc/ssl/certs/$WIKI_DOMAIN_NAME.dhparam ]; then
-      freedombone-addcert -h $WIKI_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      if [[ $LETSENCRYPT_ENABLED != "yes" ]]; then
+          freedombone-addcert -h $WIKI_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      else
+          freedombone-addcert -e $WIKI_DOMAIN_NAME -s $LETSENCRYPT_SERVER --dhkey $DH_KEYLENGTH
+      fi
       check_certificates $WIKI_DOMAIN_NAME
   fi
 
@@ -9582,7 +9602,11 @@ function install_blog {
   chown -R www-data:www-data /var/www/$FULLBLOG_DOMAIN_NAME/htdocs
 
   if [ ! -f /etc/ssl/certs/$FULLBLOG_DOMAIN_NAME.dhparam ]; then
-      freedombone-addcert -h $FULLBLOG_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      if [[ $LETSENCRYPT_ENABLED != "yes" ]]; then
+          freedombone-addcert -h $FULLBLOG_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      else
+          freedombone-addcert -e $FULLBLOG_DOMAIN_NAME -s $LETSENCRYPT_SERVER --dhkey $DH_KEYLENGTH
+      fi
       check_certificates $FULLBLOG_DOMAIN_NAME
   fi
 
@@ -9948,7 +9972,11 @@ quit" > $INSTALL_DIR/batch.sql
   configure_php
 
   if [ ! -f /etc/ssl/certs/$MICROBLOG_DOMAIN_NAME.dhparam ]; then
-      freedombone-addcert -h $MICROBLOG_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      if [[ $LETSENCRYPT_ENABLED != "yes" ]]; then
+          freedombone-addcert -h $MICROBLOG_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      else
+          freedombone-addcert -e $MICROBLOG_DOMAIN_NAME -s $LETSENCRYPT_SERVER --dhkey $DH_KEYLENGTH
+      fi
       check_certificates $MICROBLOG_DOMAIN_NAME
   fi
 
@@ -10244,7 +10272,11 @@ quit" > $INSTALL_DIR/batch.sql
   configure_php
 
   if [ ! -f /etc/ssl/certs/$HUBZILLA_DOMAIN_NAME.dhparam ]; then
-      freedombone-addcert -h $HUBZILLA_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      if [[ $LETSENCRYPT_ENABLED != "yes" ]]; then
+          freedombone-addcert -h $HUBZILLA_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      else
+          freedombone-addcert -e $HUBZILLA_DOMAIN_NAME -s $LETSENCRYPT_SERVER --dhkey $DH_KEYLENGTH
+      fi
       check_certificates $HUBZILLA_DOMAIN_NAME
   fi
 
@@ -10569,7 +10601,11 @@ function install_mediagoblin {
   echo '}' >> /etc/nginx/sites-available/$MEDIAGOBLIN_DOMAIN_NAME
 
   if [ ! -f /etc/ssl/certs/$MEDIAGOBLIN_DOMAIN_NAME.dhparam ]; then
-      freedombone-addcert -h $MEDIAGOBLIN_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      if [[ $LETSENCRYPT_ENABLED != "yes" ]]; then
+          freedombone-addcert -h $MEDIAGOBLIN_DOMAIN_NAME --dhkey $DH_KEYLENGTH
+      else
+          freedombone-addcert -e $MEDIAGOBLIN_DOMAIN_NAME -s $LETSENCRYPT_SERVER --dhkey $DH_KEYLENGTH
+      fi
       check_certificates $MEDIAGOBLIN_DOMAIN_NAME
   fi
 
@@ -11401,7 +11437,6 @@ encrypt_all_email
 import_email
 script_for_attaching_usb_drive
 install_web_server
-#install_letsencrypt
 configure_firewall_for_web_server
 install_owncloud
 install_owncloud_music_app
diff --git a/src/freedombone-addcert b/src/freedombone-addcert
index bbf1fc260..73f83eb9f 100755
--- a/src/freedombone-addcert
+++ b/src/freedombone-addcert
@@ -29,6 +29,7 @@
 # along with this program. If not, see <http://www.gnu.org/licenses/>.
 
 HOSTNAME=
+LETSENCRYPT_HOSTNAME=
 COUNTRY_CODE="US"
 AREA="Free Speech Zone"
 LOCATION="Freedomville"
@@ -37,6 +38,8 @@ UNIT="Freedombone Unit"
 EXTENSIONS=""
 NODH=
 DH_KEYLENGTH=2048
+INSTALL_DIR=/root/build
+LETSENCRYPT_SERVER='https://acme-v01.api.letsencrypt.org/directory'
 
 function show_help {
     echo ''
@@ -45,16 +48,18 @@ function show_help {
     echo ''
     echo 'Creates a self-signed certificate for the given hostname'
     echo ''
-    echo '     --help                  Show help'
-    echo '  -h --hostname [name]       Hostname'
-    echo '  -c --country [code]        Optional country code (eg. US, GB, etc)'
-    echo '  -a --area [description]    Optional area description'
-    echo '  -l --location [locn]       Optional location name'
-    echo '  -o --organisation [name]   Optional organisation name'
-    echo '  -u --unit [name]           Optional unit name'
-    echo '     --dhkey [bits]          DH key length in bits'
-    echo '     --nodh ""               Do not calculate DH params'
-    echo '     --ca ""                 Certificate authority cert'
+    echo '     --help                   Show help'
+    echo '  -h --hostname [name]        Hostname'
+    echo '  -e --letsencrypt [hostname] Hostname to use with Lets Encrypt'
+    echo '  -s --server [url]           Lets Encrypt server URL'
+    echo '  -c --country [code]         Optional country code (eg. US, GB, etc)'
+    echo '  -a --area [description]     Optional area description'
+    echo '  -l --location [locn]        Optional location name'
+    echo '  -o --organisation [name]    Optional organisation name'
+    echo '  -u --unit [name]            Optional unit name'
+    echo '     --dhkey [bits]           DH key length in bits'
+    echo '     --nodh ""                Do not calculate DH params'
+    echo '     --ca ""                  Certificate authority cert'
     echo ''
     exit 0
 }
@@ -71,6 +76,14 @@ case $key in
     shift
     HOSTNAME="$1"
     ;;
+    -e|--letsencrypt)
+    shift
+    LETSENCRYPT_HOSTNAME="$1"
+    ;;
+    -s|--server)
+    shift
+    LETSENCRYPT_SERVER="$1"
+    ;;
     -c|--country)
     shift
     COUNTRY_CODE="$1"
@@ -112,8 +125,10 @@ shift
 done
 
 if [ ! $HOSTNAME ]; then
-    echo 'No hostname specified'
-    exit 5748
+	if [ ! $LETSENCRYPT_HOSTNAME ]; then
+        echo 'No hostname specified'
+        exit 5748
+	fi
 fi
 
 if ! which openssl > /dev/null ;then
@@ -121,34 +136,94 @@ if ! which openssl > /dev/null ;then
     exit 5689
 fi
 
-CERTFILE=$HOSTNAME
-if [[ $ORGANISATION == "Freedombone-CA" ]]; then
-    CERTFILE="ca-$HOSTNAME"
+if [ ! -d /etc/ssl/mycerts ]; then
+    mkdir /etc/ssl/mycerts
 fi
 
-openssl req -x509 $EXTENSIONS -nodes -days 3650 -sha256 \
+if [ $LETSENCRYPT_HOSTNAME ]; then
+    CERTFILE=$LETSENCRYPT_HOSTNAME
+
+	if [ ! -d $INSTALL_DIR ]; then
+		mkdir -p $INSTALL_DIR
+	fi
+	cd $INSTALL_DIR
+
+	# obtain the repo
+	if [ ! -d $INSTALL_DIR/letsencrypt ]; then
+		git clone https://github.com/letsencrypt/letsencrypt
+		if [ ! -d $INSTALL_DIR/letsencrypt ]; then
+			exit 76283
+		fi
+	else
+		cd $INSTALL_DIR/letsencrypt
+		git stash
+		git pull
+	fi
+
+	cd $INSTALL_DIR/letsencrypt
+	# TODO this requires user interaction - is there a non-interactive mode?
+	./letsencrypt-auto certonly --server $LETSENCRYPT_SERVER --standalone -d $LETSENCRYPT_HOSTNAME
+	if [ ! "$?" = "0" ]; then
+		echo "Failed to install letsencrypt for domain $LETSENCRYPT_HOSTNAME"
+		exit 63216
+	fi
+
+	# replace some legacy filenames
+	if [ -f /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.bundle.crt ]; then
+		mv /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.bundle.crt /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem
+	fi
+	if [ -f /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.crt ]; then
+		mv /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.crt /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem
+	fi
+	sed -i "s|ssl_certificate /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.bundle.crt|ssl_certificate /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem|g" /etc/nginx/sites-available/$LETSENCRYPT_HOSTNAME
+	sed -i "s|ssl_certificate /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.crt|ssl_certificate /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem|g" /etc/nginx/sites-available/$LETSENCRYPT_HOSTNAME
+  
+	# link the private key
+	if [ -f /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key ]; then
+		if [ ! -f /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key.old ]; then
+			mv /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key.old
+		fi
+	fi
+	ln -s /etc/letsencrypt/live/${LETSENCRYPT_HOSTNAME}/privkey.pem /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key
+
+	# link the public key
+	if [ -f /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem ]; then
+		if [ ! -f /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem.old ]; then
+			mv /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem.old
+		fi
+	fi
+	ln -s /etc/letsencrypt/live/${LETSENCRYPT_HOSTNAME}/fullchain.pem /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem
+
+    cp /etc/letsencrypt/live/${LETSENCRYPT_HOSTNAME}/fullchain.pem /etc/ssl/mycerts/${LETSENCRYPT_HOSTNAME}.pem
+else
+    CERTFILE=$HOSTNAME
+    if [[ $ORGANISATION == "Freedombone-CA" ]]; then
+        CERTFILE="ca-$HOSTNAME"
+    fi
+
+    openssl req -x509 $EXTENSIONS -nodes -days 3650 -sha256 \
         -subj "/O=$ORGANISATION/OU=$UNIT/C=$COUNTRY_CODE/ST=$AREA/L=$LOCATION/CN=$HOSTNAME" \
         -newkey rsa:4096 -keyout /etc/ssl/private/$CERTFILE.key \
         -out /etc/ssl/certs/$CERTFILE.crt
-if [ ! $NODH ]; then
-    openssl dhparam -check -text -5 $DH_KEYLENGTH -out /etc/ssl/certs/$CERTFILE.dhparam
+    chmod 400 /etc/ssl/private/$CERTFILE.key
+    chmod 640 /etc/ssl/certs/$CERTFILE.crt
+    cp /etc/ssl/certs/$CERTFILE.crt /etc/ssl/mycerts
 fi
-chmod 400 /etc/ssl/private/$CERTFILE.key
-chmod 640 /etc/ssl/certs/$CERTFILE.crt
-chmod 640 /etc/ssl/certs/$CERTFILE.dhparam
 
-if [ -f /etc/init.d/nginx ]; then
-  /etc/init.d/nginx reload
+# generate DH params
+if [ ! $NODH ]; then
+	if [ ! -f /etc/ssl/certs/$CERTFILE.dhparam ]; then
+		openssl dhparam -check -text -5 $DH_KEYLENGTH -out /etc/ssl/certs/$CERTFILE.dhparam
+		chmod 640 /etc/ssl/certs/$CERTFILE.dhparam
+	fi
 fi
 
-# add the public certificate to a separate directory
-# so that we can redistribute it easily
-if [ ! -d /etc/ssl/mycerts ]; then
-  mkdir /etc/ssl/mycerts
+if [ -f /etc/init.d/nginx ]; then
+    /etc/init.d/nginx reload
 fi
-cp /etc/ssl/certs/$CERTFILE.crt /etc/ssl/mycerts
 
 # Create a bundle of your certificates
-cat /etc/ssl/mycerts/*.crt > /etc/ssl/freedombone-bundle.crt
-tar -czvf /etc/ssl/freedombone-certs.tar.gz /etc/ssl/mycerts/*.crt
+cat /etc/ssl/mycerts/*.crt /etc/ssl/mycerts/*.pem > /etc/ssl/freedombone-bundle.crt
+tar -czvf /etc/ssl/freedombone-certs.tar.gz /etc/ssl/mycerts/*.crt /etc/ssl/mycerts/*.pem
+
 exit 0
diff --git a/src/freedombone-controlpanel b/src/freedombone-controlpanel
index f92a94288..47a41cbd9 100755
--- a/src/freedombone-controlpanel
+++ b/src/freedombone-controlpanel
@@ -521,6 +521,30 @@ function reset_tripwire {
   any_key
 }
 
+function hubzilla_renew_cert {
+    dialog --title "Renew SSL certificate" \
+           --backtitle "Freedombone Control Panel" \
+           --yesno "\nThis will renew a letsencrypt certificate. Select 'yes' to continue" 16 60
+    sel=$?
+    case $sel in
+        1) return;;
+        255) return;;
+    esac
+    HUBZILLA_DOMAIN_NAME=$(cat $COMPLETION_FILE | grep "Hubzilla domain" | awk -F ':' '{print $2}')
+    if [ ! -d /var/www/$HUBZILLA_DOMAIN_NAME/htdocs ]; then
+       dialog --title "Renew SSL certificate" \
+              --msgbox "Hubzilla install directory not found" 6 40
+       return
+    fi
+    freedombone-renew-cert -h $HUBZILLA_DOMAIN_NAME -p 'letsencrypt'
+    if [ ! "$?" = "0" ]; then
+        any_key
+    else
+        dialog --title "Renew SSL certificate" \
+               --msgbox "Hubzilla certificate has been renewed" 6 40
+    fi
+}
+
 function hubzilla_restore {
     dialog --title "Restore hubzilla from USB backup" \
            --backtitle "Freedombone Control Panel" \
@@ -542,7 +566,7 @@ function hubzilla_channel_directory_server {
        return
     fi
     HUBZILLA_DOMAIN_NAME=$(cat $COMPLETION_FILE | grep "Hubzilla domain" | awk -F ':' '{print $2}')
-    if [ ! -d /var/www/$HUBZILLA_DOMAIN_NAME ]; then
+    if [ ! -d /var/www/$HUBZILLA_DOMAIN_NAME/htdocs ]; then
        dialog --title "Hubzilla channel directory server" \
               --msgbox "Hubzilla install directory not found" 6 40
        return
@@ -713,10 +737,11 @@ function menu_hubzilla {
         trap "rm -f $data" 0 1 2 5 15
         dialog --backtitle "Freedombone Control Panel" \
                --title "Hubzilla" \
-               --radiolist "Choose an operation:" 12 70 3 \
+               --radiolist "Choose an operation:" 13 70 4 \
                1 "Restore from usb backup" off \
                2 "Set channel directory server" off \
-               3 "Back to main menu" on 2> $data
+               3 "Renew SSL certificate" off \
+               4 "Back to main menu" on 2> $data
         sel=$?
         case $sel in
             1) break;;
@@ -725,7 +750,8 @@ function menu_hubzilla {
         case $(cat $data) in
             1) hubzilla_restore;;
             2) hubzilla_channel_directory_server;;
-            3) break;;
+            3) hubzilla_renew_cert;;
+            4) break;;
         esac
     done
 }
diff --git a/src/freedombone-renew-cert b/src/freedombone-renew-cert
index 796ce6f6c..46cda4316 100755
--- a/src/freedombone-renew-cert
+++ b/src/freedombone-renew-cert
@@ -30,6 +30,8 @@
 
 HOSTNAME=
 PROVIDER='startssl'
+DH_KEYLENGTH=2048
+LETSENCRYPT_SERVER='https://acme-v01.api.letsencrypt.org/directory'
 
 function show_help {
     echo ''
@@ -44,14 +46,28 @@ function show_help {
     exit 0
 }
 
-function renew_startssl {
-    echo "Renewing Let's Encrypt certificate"
-    letsencrypt renew \
-                --cert-path /etc/ssl/certs/$HOSTNAME.crt \
-                --key-path /etc/ssl/private/$HOSTNAME.key
-    if [ ! "$?" = "0" ]; then
-        echo "Unable to renew Let's encrypt certificate"
+function renew_letsencrypt {
+    if [ ! -f /etc/letsencrypt/live/${HOSTNAME}/fullchain.pem ]; then
+        echo "Adding Let's Encrypt certificate"
+        freedombone-addcert -e $HOSTNAME -s $LETSENCRYPT_SERVER --dhkey $DH_KEYLENGTH
+        if [ ! "$?" = "0" ]; then
+            echo "Unable to add Let's encrypt certificate"
+            exit 6328
+        fi
+    else
+        echo "Renewing Let's Encrypt certificate"
+        letsencrypt renew \
+                    --cert-path /etc/letsencrypt/live/${HOSTNAME}/fullchain.pem \
+                    --key-path /etc/letsencrypt/live/${HOSTNAME}/privkey.pem
+        if [ ! "$?" = "0" ]; then
+            echo "Unable to renew Let's encrypt certificate"
+            exit 2624
+        fi
     fi
+
+    # Ensure that links are in place
+    ln -s /etc/letsencrypt/live/${HOSTNAME}/privkey.pem /etc/ssl/private/${HOSTNAME}.key
+    ln -s /etc/letsencrypt/live/${HOSTNAME}/fullchain.pem /etc/ssl/certs/${HOSTNAME}.pem
 }
 
 function renew_startssl {
diff --git a/src/freedombone-sec b/src/freedombone-sec
index 8fd188571..1c2eeb5ee 100755
--- a/src/freedombone-sec
+++ b/src/freedombone-sec
@@ -452,7 +452,7 @@ function renew_letsencrypt {
 	  return	  
   fi
 
-  freedombone-renew-cert -h $renew_domain -p letsencrypt
+  freedombone-renew-cert -h $renew_domain -p 'letsencrypt'
 
   exit 0
 }
-- 
GitLab