2019-10-20 Dehydrated and Let's Encrypt

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

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 reload 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 miniircd (prosody is commented out), and monit.

$ cat /var/lib/dehydrated/hook.sh 
#!/bin/bash
if [ ${1} == "deploy_cert" ]; then
    echo " + Hook: Reloading Apache for ${2}..."
    service apache2 reload
    # use cat to preserve permissions
    if [ ${2} == "campaignwiki.org" ]; then
	# 3 is privkey, 4 is cert, 5 is fullchain, 6 is chain, 7 is timestamp
	echo " + Hook: Regenerating miniircd's SSL.pem file..."
	cat ${5} ${3} > /var/jail/miniircd/SSL.pem
	# service miniircd reload
	# echo " + Hook: Regenerating prosody's files..."
	# cat ${5} > /etc/prosody/certs/fullchain.pem
	# cat ${3} > /etc/prosody/certs/privkey.pem
	# service prosody reload
    elif [ ${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.

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! 😰

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

Tags:

Comments


Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. Note: in order to facilitate peer review and fight vandalism, we will store your IP number for a number of days. See Privacy Policy for more information. See Info for text formatting rules. You can edit the comment page if you need to fix typos. You can subscribe to new comments by email without leaving a comment.

To save this page you must answer this question:

Please say HELLO.