Let’s Encrypt and OpenBSD’s httpd

These instructions cover using Let's Encrypt, OpenBSD's httpd, and the acme-client program to serve websites using SSL certificates.

A caveat: these are very basic instructions from somebody who has been using httpd for a while but has just set-up SSL for the very first time. They may not make sense if you're trying to learn both httpd and how to use it with SSL.

A further caveat: these instructions only work with OpenBSD 6.1. They might work with later versions, too, but I wouldn't make any assumptions.

I am indebted to Michael W. Lucas's book Relayd and Httpd Mastery for walking me through the process. Between it, the files in OpenBSD's /etc/examples/ directory, OpenBSD's manual pages, and of course the developers' commitment to simplicity, setting up httpd is painless.

If there are mistakes below, they are solely mine.

1. Getting httpd ready

We will get our SSL certificate from a certificate provider called Let's Encrypt. We'll do this by running a program called acme-client. One of the things acme-client does is write some files and make them available on your domain, so as to prove to Let's Encrypt that you are the domain's owner.

Configure httpd and your domain to work with acme-client. This is really easy! Just configure your /etc/httpd.conf file to look mostly like this:

You just need to add

location "/.well-known/acme-challenge/*" {
root "/acme"
root strip 2
directory no auto index
}

to your /etc/httpd.conf file. As such, mine looks like this:

server "www.increasinglyadequate.com" {
    alias "increasinglyadequate.com"
    listen on egress port 80
    log style combined
    root "/htdocs/increasinglyadequate"
    # The next five lines are for acme-client:
    location "/.well-known/acme-challenge/*" {
    root "/acme"
root strip 2
directory no auto index
    }
}

Now run rcctl restart httpd so your changes take effect.

2. Getting your certificate via acme-client

acme-client is responsible for getting and renewing your certificates. The file /etc/acme-client.conf tells acme-client how to operate. Configuring this file is also very simple!

The file comes pre-loaded with the appropriate settings for Let's Encrypt. Leave these be. At the bottom of the file you will find a commented-out section containing an example configure for a domain. All you'll need to do is change the name "example.com" to whatever your domain name is. That's it.

By default, acme-client stores its files in a couple of directories. I am not a fan of this because I am slow and like everything in one place. Michael W. Lucas is smart and even he advocates a naming scheme other than the default. His scheme uses subdirectories to indicate that the files are managed through acme-client and that they pertain to a particular domain (e.g., he recommends using a directory like /etc/ssl/acme/increasinglyadequate.com/). Since I have just a couple of sites and am using just one SSL certificate provider, I'll stuff everything into /etc/ssl/. You do whatever you want.

Anyhow, my domain section for www.increasinglyadequate.com looks like this:

domain www.increasinglyadequate.com {
    alternative names { increasinglyadequate.com }
    domain key "/etc/ssl/increasinglyadequate.key"
    domain certificate "/etc/ssl/increasinglyadequate.crt"
    domain full chain certificate "/etc/ssl/increasinglyadequate.fullchain.pem"
    sign with letsencrypt
}

Note that you can have multiple domains listed in this file.

Assuming you've followed step 1 and already configured /etc/httpd.conf/ with the appropriate lines, you are ready to get your certificate.

# acme-client -vvAD www.increasinglyadequate.com

Because of the -vv flags for verbosity, you'll get a lot of output. But at the end you should see something like this:

...
acme-client: /etc/ssl/increasinglyadequate.crt: created
acme-client: /etc/ssl/increasinglyadequate.fullchain.pem: created

Verify with ls -l /etc/ssl:

# ls -l /etc/ssl/
...
-r--r--r--  1 root  wheel    2212 Jul  8 16:52 increasinglyadequate.crt
-r--r--r--  1 root  wheel    3859 Jul  8 16:52 increasinglyadequate.fullchain.pem
-r--------  1 root  wheel    3272 Jul  8 16:47 increasinglyadequate.key
...

If you get a message indicating failure, it's most likely because you haven't configured /etc/httpd.conf as in step 1 or because of some typo in /etc/acme-client.conf.

3. Setting up httpd to serve your site using SSL

This configuration file should only be used if you have completed the previous steps. In particular, if you redirect http traffic to https, but https doesn't work yet, acme-client won't be able to communicate with Let's Encrypt.

At any rate, provided you've got your SSL certificate, we can now tell httpd to serve your site using it, and we can tell httpd to redirect all http traffic to https. Just edit /etc/httpd.conf to look something like this:

# This block redirects port 80 traffic to port 443; all the actual configuration
# options can go underneath the block containing tls details.

server "www.increasinglyadequate.com" {
    alias "increasinglyadequate.com"
    listen on egress port 80
    block return 301 "https://$SERVER_NAME$REQUEST_URI"
}

server "www.increasinglyadequate.com" {
    alias "increasinglyadequate.com"
    listen on egress tls port 443
    hsts
    tls certificate "/etc/ssl/increasinglyadequate.fullchain.pem"
    tls key "/etc/ssl/increasinglyadequate.key"
    log style combined
    root "/htdocs/increasinglyadequate"
    # The next five lines are for acme-client:
    location "/.well-known/acme-challenge/*" {
root "/acme"
root strip 2
directory no auto index
    }
}

Once again, restart httpd with rcctl restart httpd. Additionally, make sure that your firewall and router allow traffic on to reach port 443 on the machine running httpd.

P.S. The hsts line should force browsers to automatically switch from http to https. As such, you may be able to omit the entire section that exists solely for redirecting http traffic, but I read that it may be best to keep both since some clients (including webcrawlers) don't use this HSTS feature.

Make sure your certificates get renewed:

The manual page for acme-client has this simple advice: "A daily cron(8) job can renew the certificates: acme-client example.com && rcctl reload httpd".

That's fine, but since this command is going to be done just once a day, I might as well let OpenBSD's daily system maintenance script take care of it. That way I can read about it with the usual daily system maintenance mail. Plus this saves me from having to fuck around with cron's syntax and from getting a separate email just about this command.

Crontab calls /etc/daily at 01:30 every day. One of /etc/daily's commands is to run the script /etc/daily.local if it exists. So I created an /etc/daily.local script that looks a bit like this:

> cat /etc/daily.local
#!/bin/sh

acme-client www.increasinglyadequate.com
acme-client blog.increasinglyadequate.com
rcctl reload httpd

Conclusion

Please bear in mind that I have very little idea of what I'm doing, that I haven't thoroughly tested these instructions, and that even if they work now, they may not work next week. If you actually want to know how all of this works, get yourself a copy of Lucas's book.