2022-11-15 Move from Dehydrated to Apache

I have a big headache, probably because I got my COVID booster yesterday. The arm also hurts. Doing dishes like Tyrannosaurus Rex. No better time than this for system administration. đŸ˜”

I recently learned from @isotopp that I can do away with Dehydrated because Apache can do the Let’s Encrypt dance, too.

@isotopp

This module manages common properties of domains for one or more virtual hosts. It serves two main purposes: for one, supervise/renew TLS certificates via the ACME protocol (RFC 8555). Certificates will be renewed by the module ahead of their expiration to account for disruption in internet services. There are ways to monitor the status of all certififcates managed this way and configurations that will run your own notification commands on renewal, expiration and errors. – mod_md

mod_md

First, comment the call to dehydrated in “/etc/cron.weekly/dehydrated”. I’m not removing it just yet.

# /home/alex/src/dehydrated/dehydrated -c

Go through the sites in “/etc/apache2/sites-enabled/” and comment the settings of SSL file locations: SSLCertificateFile, SSLCertificateKeyFile, SSLCertificateChainFile.

Create a managed domain by setting MDomain to all the domains you want managed together. These are basically the domains I had in “/etc/dehydrated/domains.txt”. Each line with one domain or more turns into a MDomain setting with one domain or more.

If ServerAdmin is not set to an email address, set MDContactEmail to an email address.

Set MDCertificateAgreement accepted.

MDomain flying-carpet.ch www.flying-carpet.ch
MDCertificateAgreement accepted
<VirtualHost *:80>
    ServerName flying-carpet.ch
    ServerAlias www.flying-carpet.ch
    Redirect permanent / https://flying-carpet.ch/
</VirtualHost>
<VirtualHost *:443>
    ServerName www.flying-carpet.ch
    Redirect permanent / https://flying-carpet.ch/
    SSLEngine on
    # SSLCertificateFile      /var/lib/dehydrated/certs/flying-carpet.ch/cert.pem
    # SSLCertificateKeyFile   /var/lib/dehydrated/certs/flying-carpet.ch/privkey.pem
    # SSLCertificateChainFile /var/lib/dehydrated/certs/flying-carpet.ch/chain.pem
    SSLVerifyClient None
</VirtualHost>
<VirtualHost *:443>
    ServerAdmin alex@gnu.org
    ServerName flying-carpet.ch
    DocumentRoot /home/alex/flying-carpet.ch
    Include conf-enabled/blocklist.conf
    <Directory /home/alex/flying-carpet.ch>
        AllowOverride All
        Require all granted
    </Directory>
    SSLEngine on
    # SSLCertificateFile      /var/lib/dehydrated/certs/flying-carpet.ch/cert.pem
    # SSLCertificateKeyFile   /var/lib/dehydrated/certs/flying-carpet.ch/privkey.pem
    # SSLCertificateChainFile /var/lib/dehydrated/certs/flying-carpet.ch/chain.pem
    SSLVerifyClient None
    ProxyPass /wiki             http://flying-carpet.ch:4024/wiki
    ProxyPass /mojo             http://localhost:8080/mojo
</VirtualHost>

You’re now ready to reload Apache.

apachectl graceful

On the server, you can now look at server stats. You usually cannot do this from the outside, for security reasons.

lynx http://localhost/server-status

If you forgot to agree, you’ll see the following:

agree to the conditions, configure “MDCertificateAgreement accepted” in your Apache. Then (graceful) restart the server to activate. Next run in ~20 seconds

Instead, you should see something like this:

  Managed Certificates

                   Domain                  Names   Status    Valid CA Stapling CheckAt Activity
   flying-carpet.ch
   flying-carpet.ch www.flying-carpet.ch
   incomplete: certificate(rsa) is missing       LetsEncrypt          Pending

Wait for a bit:

  Managed Certificates

                   Domain                  Names   Status    Valid CA                    Stapling                   CheckAt Activity
   flying-carpet.ch
   flying-carpet.ch www.flying-carpet.ch
   incomplete: certificate(rsa) is missing       LetsEncrypt          finished, 1 new certificate staged. Ongoing...

This didn’t change for many minutes until I got impatient and restarted Apache.

apachectl graceful

And now:

  Managed Certificates

        Domain           Names         Status    Valid     CA     Stapling CheckAt Activity
   flying-carpet.ch
   flying-carpet.ch www.flying-carpet.ch
   good             until 2023-02-13 LetsEncrypt       crt.sh[rsa]
   Renew 2023-01-14

OK!

The stuff is all stored in “/etc/apache2/md” (see MDStoreDir).

If you don’t want your site to be inaccessible during all that time, you’ll need to figure out, how to use MDomainSet and MDCertificateFile.

Now that this works, I can go about dismantling the rest:

There’s still something left to do. What about Monit and Prosody?

This is what “/var/lib/dehydrated/hook.sh” does:

#!/bin/bash
if [ ${1} == "deploy_cert" ]; then
    echo " + Hook: Reloading Apache for ${2}..."
    service apache2 reload
    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
    if [ ${2} == "campaignwiki.org" ]; then
	echo " + Hook: Importing certs for prosody..."
	cat ${3} > /etc/prosody/certs/campaignwiki.org.privkey.pem
	cat ${5} > /etc/prosody/certs/campaignwiki.org.fullchain.pem
	chown prosody.prosody /etc/prosody/certs/*.pem
	systemctl reload prosody
    fi
    echo " + Hook: Granting permissions to the ssl-cert group..."
    chmod g+r ${3} ${4} ${5} ${6}
else
    echo " + Hook: Nothing to do..."
fi

Now, “/etc/apache2/md/domains/alexschroeder.ch” contains a “privkey.pem” and a “pubcert.pem”. I just need a way for Monit to read them.

I created “/etc/monit/conf.d/monit.conf” and it says:

set httpd port 2812 and
    SSL ENABLE
    PEMFILE /etc/ssl/localcerts/alexschroeder.ch.all.pem
    allow admin:*secret*

So now I have to create the all-in-one PEM file.

Let’s write a new “/etc/apache2/hook.sh” and use MDMessageCmd to call it.

#!/bin/bash
domain_dir=/etc/apache2/md/domains
if [ -z "$2" ]; then
    echo Needs event and domain, e.g. hook.sh renewed alexschroeder.ch
    exit
fi
event="$1"
domain="$2"
if [ $event == "renewed" ]; then
    # Possibly reloading once for every domain in very short order? đŸ€”
    service apache2 reload
    if [ $domain == "alexschroeder.ch" ]; then
	echo "Regenerating monit's .pem file..."
	cat $domain_dir/$domain/*.pem > /etc/ssl/localcerts/alexschroeder.ch.all.pem
	service monit reload
    fi
    if [ $domain == "campaignwiki.org" ]; then
	echo "Importing certs for prosody..."
	cat $domain_dir/$domain/privkey.pem > /etc/prosody/certs/campaignwiki.org.privkey.pem
	cat $domain_dir/$domain/pubcert.pem > /etc/prosody/certs/campaignwiki.org.fullchain.pem
	chown prosody.prosody /etc/prosody/certs/*.pem
	systemctl reload prosody
    fi
    echo "Granting permissions to the ssl-cert group..."
    chmod g+r $domain_dir/$domain/*.pem
fi

I don’t remember why I needed to give the ssl-cert group read access to the PEM files. Weird.

​#Administration ​#Apache