2019-10-20 Dehydrated and Let's Encrypt

I use Dehydrated for the Let's Encrypt certificates of my web pages.

Dehydrated

Let's Encrypt

Installation wasn’t too difficult. I installed the Debian packages. This is the main config file:

$ cat **/etc/dehydrated/config**
#############################################################
# This is the main config file for dehydrated               #
#                                                           #
# This is the default configuration for the Debian package. #
# To see a more comprehensive example, see                  #
# /usr/share/doc/dehydrated/examples/config                 #
#                                                           #
# For details please read:                                  #
# /usr/share/doc/dehydrated/README.Debian                   #
#############################################################

CONFIG_D=/etc/dehydrated/conf.d
BASEDIR=/var/lib/dehydrated
WELLKNOWN="${BASEDIR}/acme-challenges"
DOMAINS_TXT="/etc/dehydrated/domains.txt"

All the domains and subdomains are listed in a separate file:

$ cat **/etc/dehydrated/domains.txt**
alexschroeder.ch www.alexschroeder.ch
arabisch-lernen.org www.arabisch-lernen.org
campaignwiki.org www.campaignwiki.org
communitywiki.org www.communitywiki.org
korero.org www.korero.org
oddmuse.org www.oddmuse.org next.oddmuse.org
orientalisch.info www.orientalisch.info
emacswiki.org www.emacswiki.org
flying-carpet.ch www.flying-carpet.ch

There are two extra config file snippets in the config directory:

$ cat **/etc/dehydrated/conf.d/contact.sh**
CONTACT_EMAIL="kensanata@gmail.com"
$ cat **/etc/dehydrated/conf.d/hook.sh**
HOOK="${BASEDIR}/hook.sh"

And now the only unexplained file is the hook I run after everything is done. This is where I restart the Apache config when a new certificate is deployed. Any other service offering TLS encrypted connections also needs to get a copy of the file and reload or restart. In my case, that’s `monit`.

$ cat **/var/lib/dehydrated/hook.sh**
#!/bin/bash
if [ ${1} == "deploy_cert" ]; then
    echo " + Hook: restarting Apache for ${2}..."
    apachectl graceful
    if [ ${2} == "alexschroeder.ch" ]; then
	echo " + Hook: Regenerating monit's .pem file..."
	# 3 is privkey, 4 is cert, 5 is fullchain, 6 is chain, 7 is timestamp
	cat ${5} ${3} > /etc/ssl/localcerts/alexschroeder.ch.all.pem
	service monit reload
    fi
else
    echo " + Hook: Nothing to do..."
fi

But wait, the web server also needs to know what to do with the *Let’s Encrypt* challenges. Luckily, Debian already created this for us!

$ cat **/etc/apache2/conf-enabled/dehydrated.conf**
#
# Apache configuration to serve http-01 ACME challenges responses.
# This is included from the dehydrated-apache2 package, thought to be used
# with dehydrated as packaged in Debian.

<IfModule proxy_module>
    # Do not proxy ACME challenge responses
    ProxyPass /.well-known/acme-challenge/ !
</IfModule>
<IfModule !alias_module>
    # Load the alias module, if not loaded already
    Include /etc/apache2/mods-available/alias.load
    Include /etc/apache2/mods-available/alias.conf
</IfModule>
<IfModule alias_module>
    # Serve ACME challenge responses
    Alias /.well-known/acme-challenge/ /var/lib/dehydrated/acme-challenges/
</IfModule>

<Directory /var/lib/dehydrated/acme-challenges/>
    Options FollowSymlinks
    Options -Indexes
    AllowOverride None
    # Apache >= 2.3
    <IfModule mod_authz_core.c>
        Require all granted
    </IfModule>
    # Apache < 2.3
    <IfModule !mod_authz_core.c>
        Order Allow,Deny
        Allow from all
    </IfModule>
</Directory>

In order to run it, There is a weekly `cron` job.

$ cat **/etc/cron.weekly/dehydrated**
#!/bin/sh
/usr/bin/dehydrated -c

Every week I’m getting a report by mail telling me how it went. 🙂 For an example of what the email looks like, check my old post from 2016.

old post from 2016

We’re still not done, yet. The actual websites also need to be told how to get the certificates. Here are the important lines from the first site, using Apache.

Port 80 is ordinary HTTP which works for both `alexschroeder.ch` and `www.alexschroeder.ch`. It redirects to port 443 on `alexschroeder.ch`.

Port 443 uses HTTPS for `www.alexschroeder.ch` and also redirects to port 443 on `alexschroeder.ch`. As it uses HTTPS, it needs the SSL directives to tell it where to find the certificates `dehydrated` saves on our system.

And finally, port 443 using HTTPS for `alexschroeder.ch` is the real site. There are more settings there, of course. It uses the same SSL directives as we listed the domain and the `www` subdomain on a single line in our list of domains for `dehydrated`.

$ cat /etc/apache2/sites-enabled/100-alexschroeder.ch.conf
<VirtualHost *:80>
    ServerName alexschroeder.ch
    ServerAlias www.alexschroeder.ch
    Redirect permanent / https://alexschroeder.ch/
</VirtualHost>
<VirtualHost *:443>
    ServerName www.alexschroeder.ch
    ServerAlias rpg.alexschroeder.ch
    Redirect permanent / https://alexschroeder.ch/
    SSLEngine on
    SSLCertificateFile      /var/lib/dehydrated/certs/alexschroeder.ch/cert.pem
    SSLCertificateKeyFile   /var/lib/dehydrated/certs/alexschroeder.ch/privkey.pem
    SSLCertificateChainFile /var/lib/dehydrated/certs/alexschroeder.ch/chain.pem
    SSLVerifyClient None
</VirtualHost>
<VirtualHost *:443>
    ServerAdmin alex@alexschroeder.ch
    ServerName alexschroeder.ch
    DocumentRoot /home/alex/alexschroeder.ch
    <Directory /home/alex/alexschroeder.ch>
        Options ExecCGI Includes Indexes MultiViews SymLinksIfOwnerMatch
	# There are still legacy CGI scripts in here
        AddHandler cgi-script .pl
        AllowOverride All
        Require all granted
    </Directory>

    Include conf-enabled/blocklist.conf

    SSLEngine on
    SSLCertificateFile      /var/lib/dehydrated/certs/alexschroeder.ch/cert.pem
    SSLCertificateKeyFile   /var/lib/dehydrated/certs/alexschroeder.ch/privkey.pem
    SSLCertificateChainFile /var/lib/dehydrated/certs/alexschroeder.ch/chain.pem
    SSLVerifyClient None

    ...

</VirtualHost>

Troubleshooting

Are we done? Not quite!

For a while now, I’ve been getting the following error:

  + ERROR: An error occurred while sending post-request to https://acme-v01.api.letsencrypt.org/acme/new-authz (Status 400)

Details:
{
  "type": "urn:acme:error:badNonce",
  "detail": "JWS has no anti-replay nonce",
  "status": 400
}

Uggggh... See issue #684. The solution is to switch to the master branch, for now. Check out `dehydrated` from the `git` repository and overwrite the copy installed by your system’s package manager? Or call your local copy in the working directory from the weekly `cron` job? Do it manually once a week? Bad solutions all around! 😰

#684

You’ll have to do that until the package gets updated, I’m afraid.

​#Web ​#Administratino ​#Cryptography ​#Dehydrated

Comments

(Please contact me if you want to remove your comment.)

Here’s @withaveeay, writing about uacme:

@withaveeay

Two options, which are attractive, acme.sh and dehydrated, were started as individual projects, but were both quietly bought by corporates. That’s no bad thing in itself, and the licensing should offer some protection against corporate excess, but both already showed signs of preferring the offerings of their new corporate owners. … Then I noticed that one simple utility, written in C, simply retrieves certificates using the ACME protocol. That’s all it does. Even validation needs to be done by a separate script, although this is supplied. It’s very much the unix way of doing things. … So I started looking at uacme. – Letsencrypt cerficates - all change from certbot

Letsencrypt cerficates - all change from certbot

The blog post about the sale of dehydrated:

A few days ago I was approached by Julian from … who told me that they wanted to buy dehydrated as a project and that they would even like to pay me to continue working on it. At first I thought it was a joke, but Julians profile seemed legit and after a few messages it was clear they really wanted to have my project. They made an acceptable offer and after a good night’s sleep I agreed. – Selling dehydrated

Selling dehydrated

The post about changes to acme.sh:

Starting from August-1st 2021, acme.sh will release v3.0, in which the default CA will use ZeroSSL instead. – The acme.sh will change default CA to ZeroSSL on August-1st 2021

The acme.sh will change default CA to ZeroSSL on August-1st 2021

– Alex 2022-06-09 07:47 UTC

---

See 2022-11-15 Move from Dehydrated to Apache.

2022-11-15 Move from Dehydrated to Apache

– Alex 2022-11-15 16:41 UTC