Let’s Encrypt with Certbot

Can I use the EFF’s Certbot to set up TLS encryption on my server?

Part 7 of the Running to Stand Still series.

A Little Knowledge

One reason I thought I could not enable TLS before now is that the SSL handshake used to establish a server’s identity requires that each server have a unique IP address. This would be a problem given I have 69 domain names in my NGINX configuration!

Turns out there are TLS features to support this use case.

  • The terminology used is confusing, but TLS supports a SAN (Server Alternate Name) property and hence a flavour of certificate called Unified Communication Certificate (UCC), which might or might not just mean a certificate with a SAN field—but in any case it appears a single certificate can give multiple domain names to a given IP address.

  • SNI (Server Name Indication) is like the HTTP header Host: it tells the server which domain name it needs to prove itself to be so that it can proffer the correct certificate, and hence allows for a single IP address to be protected by a collection of certificates.

So it appears this restriction has been lifted.

So Many Domains

I created a throwaway script to find how many domain names I had created:

import os
import re

server_name_re = re.compile(
    r""" ^ \s* server_name \s+ ([^;]+) ; """,
    re.VERBOSE | re.MULTILINE | re.DOTALL)

src_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'src')
names = set()
for dir_path, dir_names, file_names in os.walk(src_dir):
    for file_name in file_names:
        file_path = os.path.join(dir_path, file_name)
        with open(file_path, 'r') as input:
            text = input.read()
        for m in server_name_re.finditer(text):
            names.update(m.group(1).split())

print('-d', ','.join(sorted(names, key=lambda n: tuple(reversed(n.split('.'))))))

There are 69 partly because most of my sites have at least 5:

  • kanbo.me.uk
  • ip4.kanbo.me.uk
  • ip6.kanbo.me.uk
  • static.kanbo.me.uk
  • www.kanbo.me.uk

The www subdomain exists to redirect to the canonical one. I serve static files (style sheets, images, etc.) from the static subdomain. The ip4 and ip6 subdomains are aliases for kanbo.me.uk that are IPv4- and IPv6-only (I had some vague idea it would be nice to see whether I could show that IPv6 exists). I added them when I was updating my server to support IPv6 and I probably don’t need them now.

Actually there are only 69 if I include localhost.

Certbot Knows All?

The documentation for Let’s Encrypt and Certbot are designed to reassure nervous non-technical people, which unfortunately is just the thing that makes technical people nervous.

I have a few questions

  • Does it handle IPv6 as well as IPv4 addresses?
  • Will the way I organize my domain names present any issues?
  • Will the way I organise my NGINX configuration present any issues?

For now all I can do is assume that the Certbot programmers have thought through these problems and can address them without any help from the user.

Just to be on the safe side I have copied my configuration from the server and created a local Git repo for it. This will allow me to see the details of the changes made by Certbot and generally act as a backup for the config.

Missing domains

I ran Certbot using the -d argument generated by the script and got this message back telling me some of my ip4 and ip6 domains had come back NXDOMAIN. One was a simple omission—I added the subdomains to NGINX but neglected to update the DNS; the solution is to update the DNS records and, since this requires migrating them to my provider’s newer DNS system, waiting a day or two for the new setup to propagate.

The other is the CAPTION site, which is not on my Gandi account. I cannot at this moment remember who owns the domain or how its DNS is edited these days, but probably the right thing to do for now is to drop the CAPTION domain names from my certificate request.

One More Thing

After running Certbot again and letting it have its way with my .conf files, I pointed my browser at http://alleged.org.uk/ and it redirected to https://alleged.org.uk/, which was great apart from the missing style sheet and images.

This was of course caused by the fact I set the STATIC_URL environment variable to http:///static.alleged.org.uk/ and Safari was not loading non- encrypted resources from my encrypted page. The fix was simple enough:

echo //static.alleged.org.uk/ | sudo tee /service/alleged/env/STATIC_URL
sudo svc -du /service/alleged

Similar little tweaks will be required on other sites, unfortunately.