A Let's Encrypt client feature I always want for easy standard deployment

June 19, 2019

On Twitter, I said:

It bums me out that Certbot (the 'official' Let's Encrypt client) does not have a built-in option to combine trying a standalone HTTP server with a webroot if the standalone HTTP server can't start.

(As far as I can see.)

For Let's Encrypt authentication, 'try a standalone server, then fall back to webroot' lets you create a single setup that works in a huge number of cases, including on initial installs before Apache/etc has its certificates and is running.

In straightforward setups, the easiest way to prove your control of a domain to Let's Encrypt is generally their HTTP authentication method, which requires the host (or something standing in for it) to serve a file under a specific URL. To do this, you need a suitably configured web server.

Like most Let's Encrypt clients, Certbot supports both putting the magic files for Let's Encrypt in a directory of your choice (which is assumed to already be configured in some web server you're running) or temporarily running its own little web server to do this itself. But it doesn't support trying both at once, and this leaves you with a problem if you want to deploy a single standard Certbot configuration to all of your machines, some of which run a web server and some of which don't. And on machines that do run a web server, it is not necessarily running when you get the initial TLS certificates, because at least some web servers refuse to start at all if you have HTTPS configured and the TLS certificates are missing (because, you know, you haven't gotten them yet).

Acmetool, my favorite Let's Encrypt client, supports exactly this dual-mode operation and it is marvelously convenient. You can run one acmetool command no matter how the system is configured, and it works. If acmetool can bind to port 80, it runs its own web server; if it can't, it assumes that your webroot setting is good. But, unfortunately, we need a new Let's Encrypt client.

For Certbot, I can imagine a complicated scheme of additional software and pre-request and post-request hooks to make this work; you could start a little static file only web server if there wasn't already something on port 80, then stop it afterward. But that requires additional software and is annoyingly complicated (and I can imagine failure modes). For extra annoyance, it appears that Certbot does not have convenient commands to change the authentication mode associated configured for any particular certificate (which will be used when certbot auto-renews it, unless you hard-code some method in your cron job). Perhaps I am missing something in the Certbot documentation.

(This is such an obvious and convenient feature that I'm quite surprised that Certbot, the gigantic featureful LE client that it is, doesn't support it already.)

Comments on this page:

I have a trick for bootstrapping Apache: when I first install a web server I link to Debian’s self-signed “snakeoil” cert, so Apache will agree to start, then after dehydrated has run I swing the links over to the real certs. It is a little bit of scripting but not too bad - details at https://www.dns.cam.ac.uk/news/2019-03-15-lets-encrypt.html

By cks at 2019-06-19 16:09:56:

The problem with this trick for us is that the paths to certificates in various configuration files is host-specific, eg currently we say that a key is '/var/lib/acme/live/<name>/privkey', for various names (and sometimes more than one on the same server). Even if we pointed them to some directory under our control, we are never going to have just one certificate on all hosts, with a common path.

From at 2019-06-19 18:32:19:

Even if we pointed them to some directory under our control, we are never going to have just one certificate on all hosts, with a common path.

Can't this be done with --deploy-hook? With-in the script do:

  • rm /etc/ssl-certs/fullchain.pem.old && \
  • mv /etc/ssl-certs/fullchain.pem /etc/ssl-certs/fullchain.pem.old && \
  • ln -s ${RENEWED_LINEAGE}/fullchain.pem /etc/ssl-certs/fullchain.pem
  • etc.
  • ln -s ${RENEWED_LINEAGE}/privkey.pem /etc/ssl-certs/privkey.pem

Double-check before restarting Apache (or whatever):

  • ( apache2ctl configtest && service apache restart ) || echo "Complain loudly."

If anything goes wrong, the "configtest" will error-out and cron with throw an error, leaving your web server still up with a valid cert for another 30 days to see what went wrong.

We use Let's Encrypt, but still put all the certs it takes care of under Nagios monitoring for cert expiration in case something breaks and we don't notice the cron message.

By cks at 2019-06-20 00:43:12:

We have various servers (not just web servers, although they're the leading case) with multiple certificates for different sets of names. This means we couldn't use a fixed static name for keys and certs.

(We've also found that it simplifies operation if the name and source of the certificate is right there in the name. A /etc/ssl-certs/fullchain.pem could come from anywhere and be for anything. /etc/letsencrypt/live/<name>/... is clearly from Certbot and is for a given name, and that makes it obvious what Apache, Dovecot, Exim, etc need for certificate setup.)

From at 2019-06-22 08:23:23:

The --deploy-hooks option also has the $RENEWED_DOMAINS env variable that may be useful. More info:

Personally, I haven't used certbot in production as it just seems 'complicated' to me for some reason. After acmetool (now depreciated / abandoned (?)), I ran across dehydrated and it works for most of the situations we have at work, and I find it much easier to grasp: put stuff in some config files where you don't want the (generally-sane) defaults, edit the hook.sh shell script to suit one's needs, and run dehydrated -c.

Written on 19 June 2019.
« Sometimes, the problem is in a system's BIOS
How Bash decides it's being invoked through sshd and sources your .bashrc »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Jun 19 01:13:03 2019
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.