Let’s Encrypt on …. any Linux distro!

Posted 13 February, 2016

If you did not know yet, I’m a huge fan of Let’s Encrypt, however, we need to give them some slack, they only publicly announced 1 year, 2 months, 26 days, 18 hours and 13 minutes ago.  In that time they created the entire backbone, code and structure to start giving out validated certificates, for free.  They currently have a beta sticker on still, and I do agree, there github account is still very active with over 150 contributors pitching in.  The official client however has many dependencies, that many in fact that Centos 6 has only recently been supported. But what about Centos 5 ? or older Ubuntu LTS ? or any other Linux Distro ? What about when my apps are using a not supported python ?  Well that is where the Linux community shines most, someone thinks I can do this different and so Lukas Schauer (personal website) created a super tiny (821 lines) low-requirement shell script called dehydrated.  I still have little experience when it comes to certificates and https in general, but getting you’re visitors a encrypted line to visit is now easier then ever !


Most Linux distro’s will have this already installed, so this should not make a problem. I’m using a Centos 32bit VPS for this example, but this should be doable for pretty much any Linux distro.

yum install nano wget curl sed grep mktemp git

That’s it, for me only nano and wget had to be installed on a Centos minimal! (note : nano or …)


Its a bash script! Either download and chmod or download the entire package using git.

cd /opt
git clone https://github.com/lukas2511/dehydrated.git
cd dehydrated/


You could run everything from console, but for automation it might be a good idea to configure it in a script itself. For that purpose it uses a file named config.sh. There is also a file domains.txt for the domain names. I copied the example :

cp docs/examples/config config.sh
ln -s config.sh config

In config.sh remove the # (hashtag) from all value’s, the defaults should work well. The only exceptions are :


and (change the e-mail address in to a working one!)

CONTACT_EMAIL="[email protected]"

Now we need to create a file /opt/dehydrated/domains.txt there you need to add domain names you wanne get a certificate for. I tested it with one subdomain :


and that worked, however if you want multiple use :

svennd.be test.svennd.be alfa.svennd.be

Would validate svennd.be, test.svennd.be and alfa.svennd.be in one certificate, (as alternatives) You can also read up on the github,

That’s it for configuration!

Setting up the environment

For this server I am using Apache, you will have to find how to get this working with others webservers.

First make the directory (WELLKNOWN) we have used in the configuration :

mkdir /var/www/dehydrated/

warning : using /home as WELLKNOWN might give problems on a default Apache installation. (you would need mod_userdir)

On a clean install this was the config I used, most likely parts will already be there: (read comments)

# allow multiple hosts on 1 IP
NameVirtualHost *:80

<VirtualHost *:80>
# documentroot
DocumentRoot /var/www/html

# servername
ServerName test.svennd.be
# vital :
Alias /.well-known/acme-challenge /var/www/dehydrated/

# this might not be needed
<Directory "/var/www/dehydrated/">
   Header add Content-Type text/plain


Restart apache with service httpd restart , and then go ahead and create you’re certificate!

Creating a certificate

Now getting to the easy part, getting the certificate :

./dehydrated -c

This should result in something as :

Let’s Encrypt the web, this is where my https story began!

This will generate :

├── certs
│   └── domain.tld
│       ├── cert.csr
│       ├── cert.pem
│       ├── fullchain.pem
│       └── privkey.pem
├── config.sh
├── domains.txt
├── dehydrated
├── private_key.pem
└── README.md

From there you could just use this tutorial for adding it to apache.


During the testing I made some errors, you might encounter them as well.

Challenge invalid
ERROR: Challenge is invalid! (returned: invalid) (result: {"type":"http-01","status":"invalid","error":{"type":"urn:acme:error:unauthorized","detail":"Invalid response from http://domain.tld/.well-known/acme-challenge/[]: 500"},"uri":"https://acme-v01.api.letsencrypt.org/acme/challenge/","token":"","keyAuthorization":".-","validationRecord":[{"url":"http://domain.tld/.well-known/acme-challenge/","hostname":"domain.tld","port":"80","addressesResolved":[""],"addressUsed":""}]})

This happened for me when the directory was not accessible. Settings where wrong, be sure to test it with creating test files  (touch /my/.well-known/test.html) and then hitting them on the webserver.

No registration exists matching provided key
./dehydrated --cron
# INFO: Using main config file /opt/dehydrated/config.sh
Processing domain.tld
 + Signing domains...
 + Creating new directory /opt/dehydrated/certs/domain.tld ...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for domain.tld...
  + ERROR: An error occurred while sending post-request to https://acme-v01.api.letsencrypt.org/acme/new-authz (Status 403)

{"type":"urn:acme:error:unauthorized","detail":"No registration exists matching provided key","status":403}

This weird one happened when 1) I did not enter a valid e-mail address and 2) an e-mail adres that was used by another domain.


While the official method surely should be default, due to the way ACME is setup, Let’s Encrypt allows for other clients, one of these is a very simple shell script, and that works in even the most variable environments.  A big thanks to lukas2511 and Let’s Encrypt for making this possible! Happy Encrypting !

Changes :

  • Letsencrypt.sh has been renamed to dehydrated for legal reasons.
  • Slightly adapted the guide to reflect where config.sh comes from, also renamed some old letsencrypt.sh references to dehydrated. (13/03/2017)

Show Comments (10)
© SvennD