Tools Let's Encrypt Lead image: Lead Image © Stuart Miles, 123RF.com
Lead Image © Stuart Miles, 123RF.com
 

Getting a free TLS certificate from Let's Encrypt

Certified

A free TLS certificate from Let's Encrypt means you can add encryption to your network for no cost, so you don't have any more excuses for failing to encrypt. By Hans-Cees Speel

Let's Encrypt [1] is an open-source project with the goal of making sure every website is encrypting with TLS. The Let's Encrypt project is sponsored by organizations such as Mozilla, Cisco, Akamai, EFF, gandi.net, and many more. The primary role of Let's Encrypt is to offer trusted and free TLS certificates for everyone. Users can even copy and integrate Let's Encrypt technology into their own networks, which means any website can now offer a encrypted option for no cost. On May 8th 2016, Let's Encrypt issued its one millionth certificate.

Building in Trust

Let's Encrypt requires that whoever requests a certificate must prove they control the website for which the certificate is intended. If you wish to receive the certificate for a website, the DNS entry for the domain must point to your IP address in DNS.

To request a certificate for http://www.hanscees.com, I had to run a script on the web server serving http://www.hanscees.com, asking the Let's Encrypt staging-server (LSS) for the certificate. The LSS asks the web server to present a secret file on a subdirectory of the website, checks it, and, if successful, hands over a certificate file. See the Let's Encrypt website for additional information [2].

You can use Let's Encrypt for any website regardless of the web server. For my home-grown sites, I use one ESXI VMware server and deploy pre-installed virtual machines using TurnKey Linux [3], a Debian-based series of pre-configured Linux application hosts. Deploying a new website takes me about 10 minutes.

To secure websites running on Joomla or other web-based applications, I use a front-end reverse-proxy. I recently switched from Nginx to Hiawatha [4] because the Hiawatha configuration makes it extremely easy to protect websites from SQL attacks. A front-end reverse proxy makes using Let's Encrypt much easier: instead of having to use a Let's Encrypt client on every web server, I can renew certificates for many back-end web servers in one script using one machine.

Getting a Free Let's Encrypt SSL/TLS Certificate

Let's Encrypt was a public beta when I wrote this article, and some of the procedures have changed, but this brief introduction will help you get started. Also, keep in mind that you might need to adjust these procedures based on your own configuration.

Consider taking a snapshot of your system or exporting the VM to be sure you can easily revert to the previous configuration in case of a problem.

To set up Let's Encrypt:

cd /root
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto --server https://acme-v01.api.letsencrypt.org/directory --help

Now get some coffee and wait for a long download.

The first time you get a certificate, you need to run the commands manually, because you need to enter some manual input, such as an email address. Also, make sure you test with the staging server while you're learning how to use Let's Encrypt, because the real server has some built-in limits: if you try too many times, it will block certificate renewal for your domain for a week.

Start with the test server:

https://acme-staging.api.letsencrypt.org/directory

After you understand how Let's Encrypt works, you can try this using the production server:

https://acme-v01.api.letsencrypt.org/directory

To obtain a non-signed test certificate, change to the letsencrypt directory:

cd /root/letsencrypt

The basic command for obtaining a certificate is:

./letsencrypt-auto certonly -a webroot --webroot-path /srv/www/example.com/ -d example.com -d www.example.com --server https://acme-staging.api.letsencrypt.org/directory

Next, you need to make sure:

If you are testing a couple of times, make sure you keep a backup of your Let's Encrypt credentials:

tar -cvzf /root/letsencrypt.tgz /etc/letsencrypt

On my network, I enter:

./letsencrypt-auto certonly -a webroot --webroot-path /var/www/backends/ -d www.test-backend.com --server https://acme-staging.api.letsencrypt.org/directory

After you enter the command, you have to type an email address and agree to the terms of service [5]. If all goes well, you will get a message similar to the output shown in Listing 1.

Listing 1: Successful Certificate

Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/www.test-backend.com /fullchain.pem. Your
   cert will expire on 2016-03-27. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.
If you like Let's Encrypt, please consider supporting our work by:
   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

If you are continually testing and getting errors saying the archive directory already exists, you might need to clean up some directories:

cd /etc/letsencrypt/
rm -rf archive/www.test-backend.com*
rm -rf live/www.test-backend.com*
rm -rf renewal/www.test-backend.com*
rm -rf keys/*
rm -rf csr/*

To use the Let's Encrypt certificate with Hiawatha, you need to process the files to the right format:

cd /etc/letsencrypt/live/www.test-backend.com/
cat privkey.pem cert.pem chain.pem > hiawatha-hc.pem
chown www-data:www-data hiawatha-hc.pem
chmod 440 hiawatha-hc.pem

When you have a new certificate, you must restart so the web server can use it:

service hiawatha check
/etc/init.d/hiawatha restart

Now point your browser to the website and see if you get redirected to HTTPS or receive a warning because you are using the test environment and the certificate is not trusted.

Ignore the warnings and have a look at the certificate: mine was signed by "happy hacker fake CA."

A Real Certificate

Now that you have the process working, you can get a trusted certificate signed by Let's Encrypt.

First, clean up the testing stuff:

tar -cvzf /root/letsencrypt.tgz /etc/letsencrypt
cd /etc/letsencrypt/
rm -rf archive/www.test-backend.com*
rm -rf live/www.test-backend.com*
rm -rf renewal/www.test-backend.com*

Next, get a the real signed certificate as follows:

cd /root/letsencrypt
./letsencrypt-auto certonly -a webroot --webroot-path /var/www/backends/ -d www.test-backend.com --server https://acme-v01.api.letsencrypt.org/directory

If a congratulations follows, you can prep the cert (remember this is for Hiawatha, the instructions will vary if you use a different web server):

cd /etc/letsencrypt/live/www.test-backend.com/
cat privkey.pem cert.pem chain.pem > hiawatha-hc.pem
chown www-data:www-data hiawatha-hc.pem
chmod 440 hiawatha-hc.pem

Restart Hiawatha, and you should see your website without HTTPS warnings. If you examine the certificate, you'll see that it says:

Issued by: Let's Encrypt Authority X1

You now have an officially signed and trusted certificate. Your website just became one of many secured sites using Let's Encrypt for a safer internet.

Automating Renewal

The Let's Encrypt certificates are designed to expire in three months. This expiration ensures the certificates are "always fresh" and, after a breach, they cannot be used for long.

This short lease period means you might want to automate renewal to save yourself the trouble of repeating the installation process.

For the first renewal, I recommend letting cron take care of it, but then do a check to ensure that all went well. I scripted a proof-of-concept renewal script that I run every week (Listing 2). In addition, I have a second script that alerts me on certificates that are about to expire. The script in Listing 2 does the job, but please post better scripts as you make them. The script will probably work if:

Listing 2: Automated Renewal

01 #!/bin/bash
02 # hanscees@hanscees.com version 27-03-2016
03 #This script will renew one or multiple Let's Encrypt domains
04 # by default it uses the staging server. Adjust to use life Let's Encrypt server
05 # Let me know if you built a better script
06
07 WEBROOT="/var/www/backends/"
08 #we will get certificates for the following domains
09 DOMAINS="www.test-backend.com www.backend.com www.backend.net" #adjust
10 EMAILADMIN="hanscees@hanscees.con" #adjust
11
12 LECROOT="/etc/letsencrypt/live"
13 mkdir /root/letsencrypt #justincase
14
15 #lets get certs
16 echo "will get the certs now" & sleep 3
17 for i in `echo $DOMAINS` ; do
18 echo "getting certs for  $i"
19
20 #If certs do not exist yet
21 FILE="$LECROOT/$i/cert.pem"
22 if [ ! -f "$FILE" ]
23 then
24         echo "$FILE does not exists, so lets get certificates"
25         cd /root/letsencrypt
26         #using staging server? Adjust if neccesary
27         ./letsencrypt-auto certonly -a webroot --webroot-path $WEBROOT -d $i --server \
28         https://acme-staging.api.letsencrypt.org/directory
29         #./letsencrypt-auto certonly -a webroot --webroot-path $WEBROOT -d $i --server \
30         https://acme-v01.api.letsencrypt.org/directory
31         sleep 33 # can take a while
32 else
33         echo "there is already a certificate, lets test its age"
34         sleep 3
35
36         #only get certs if the current certs arent very youngh: age test
37         if test `find "$LECROOT/$i/cert.pem" -mtime +71`
38         then
39                 echo "certificates exist and are rather old"
40                 # so lets get new ones
41                 cd /root/letsencrypt
42                 #using staging server? Adjust if neccesary
43                 ./letsencrypt-auto certonly -a webroot --webroot-path $WEBROOT -d $i \
44                 --server https://acme-staging.api.letsencrypt.org/directory
45                 #./letsencrypt-auto certonly -a webroot --webroot-path $WEBROOT -d $i \
46                 --server https://acme-v01.api.letsencrypt.org/directory
47                 sleep 33 # can take a while
48         else
49                 echo " certificates exist, but apparently are very fresh, do not get new ones"
50                 sleep 3
51                 # notify and exit this loop iteration, continuing with the next
52                 echo "certificate $i not refreshed, they are very new so no problem" |
53                 mail -s no-need-refresh-cert-$i $EMAILADMIN
54                 continue
55         fi # age test
56
57 fi # does cert file exist
58
59
60 #if all is well we have a new certificate, but we need to adjust it to hiawatha pem format
61 #check if pems are indeed new, or skip, could be an error right?
62 #cd $LECROOT/$i
63 if test `find "$LECROOT/$i/cert.pem" -mmin +3600`
64 then
65         # certificates are old, not refreshed, has been an error
66         # notify and exit this loop iteration, continuing with the next
67         echo "certificate $i not refreshed, send fire department" | mail -s problem-cert-$i $EMAILADMIN
68         continue
69 else
70         # certs are fresh, so lets make a new pem  #adjust for non-hiawatha webserver
71         echo "certs $i are in lets make a pem"
72         cat $LECROOT/$i/privkey.pem $LECROOT/$i/cert.pem $LECROOT/$i/chain.pem > $LECROOT/$i/hiawatha-hc.pem
73         chown www-data:www-data  $LECROOT/$i/hiawatha-hc.pem
74         chmod 440 $LECROOT/$i/hiawatha-hc.pem
75         echo "pemfile is $LECROOT/$i/hiawatha-hc.pem"
76 fi
77 done
78
79 # todo, built in some test?
80 /etc/init.d/hiawatha restart #adjust
81
82 echo "letsencrypt certificates $DOMAINS update just ran, sending email to $EMAILADMIN"
83 echo "letsencrypt certificates $DOMAINS update just ran, please check your websites" |
84 mail -s "letsencrypt-update-$DOMAINS" $EMAILADMIN

To create the script, enter

mkdir /root/scripts
vi /root/scripts/updatecerts

and copy the lines in Listing 2 to the updatecerts file. Then, change the permissions for the file with the following:

chmod +x /root/scripts/updatecerts

Make the necessary modifications to the lines labeled #adjust, and run the script with:

/root/scripts/updatecerts

If you want to run this script from cron every 4 weeks or so, add a line like the following to cron:

cron crontab -e
30 03 01 */2 * /root/scripts/updatecerts >> /var/log/cron.log 2>&1

If you will be using this script, I strongly recommend you run it a few times manually using the stage area!

To check if your certificates will expire within 4 weeks, you can run the script shown in Listing 3.

Listing 3: expire-check

01 #!/bin/bash
02 # hanscees@hanscees.com version 28-12-2015
03
04 DOMAINS="www.test-backend.com www.thisisagreatwebsite.com"   #adjust
05 EMAILADMIN="hanscees@hanscees.con"    # adjust
06
07 LECROOT="/etc/letsencrypt/live"
08 for i in `echo $DOMAINS` ; do
09 #checkend is seconds. 1 week = 604800 sec 4 weeks 2419200 16 weeks = 9676800
10   if openssl x509 -checkend  2419200 -noout -in $LECROOT/$i/cert.pem
11   then
12     echo "Certificate is good for another 4 weeks!"
13   else
14     echo "Certificate $i will expire within 4 weeks! (or is invalid/not found)"
15     echo "Certificate $i will expire within 4 weeks! (or is invalid/not found)" |
16     mail -s "TLS certificate $i will expire act now" $EMAILADMIN
17 fi
18 done #end forloop

Conclusion

In this article, I described how to get a free trusted TLS certificate on a Linux web server and also how you

might automate the process, because you will need to refresh your certificates. Have fun setting up many TLS-protected websites with Let's Encrypt.