Let's Encrypt with OpenBSD and Rex

Published at 2022-07-30T12:14:31+01:00

I was amazed at how easy it is to automatically generate and update Let's Encrypt certificates with OpenBSD.

Table of Contents

What's Let's Encrypt?

Let's Encrypt is a non-profit certificate authority run by Internet Security Research Group that provides X.509 certificates for Transport Layer Security (TLS) encryption at no charge. It is the world's largest certificate authority, used by more than 265 million websites, with the goal of all websites being secure and using HTTPS.

Source: Wikipedia

In short, it gives away TLS certificates for your website - for free! The catch is, that the certificates are only valid for three months. So it is better to automate certificate generation and renewals.

Meet `acme-client`

`acme-client` is the default Automatic Certifcate Management Environment (ACME) client on OpenBSD and part of the OpenBSD base system.

When invoked, the client first checks whether certificates actually require to be generated.

Oversimplified, the following steps are undertaken by `acme-client` for generating a new certificate:

Configuration

There is some (but easy) configuration required to make that all work on OpenBSD.

acme-client.conf

This is how my `/etc/acme-client.conf` looks like (I copied a template from `/etc/examples/acme-client.conf` to `/etc/acme-client.conf` and added my domains to the bottom:

httpd.conf

For ACME to work, you will need to configure the HTTP daemon so that the "special" ACME requests from Let's Encrypt are served correctly. I am using the standard OpenBSD `httpd` here. These are the snippets I use for the `foo.zone` host in `/etc/httpd.conf` (of course, you need a similar setup for all other hosts as well):

As you see, plain HTTP only serves the ACME challenge path. Otherwise, it redirects the requests to TLS. The TLS section then attempts to use the Let's Encrypt certificates.

It is worth noticing that `httpd` will start without the certificates being present. This will cause a certificate error when you try to reach the HTTPS endpoint, but it helps to bootstrap Let's Encrypt. As you saw in the config snippet above, Let's Encrypt only requests the plain HTTP endpoint for the verification process, so HTTPS doesn't need to be operational yet at this stage. But once the certificates are generated, you will have to reload or restart `httpd` to use any new certificate.

CRON job

You could now run `doas acme-client foo.zone` to generate the certificate or to renew it. Or you could automate it with CRON.

I have created a script `/usr/local/bin/acme.sh` for that for all of my domains:

And added the following line to `/etc/daily.local` to run the script once daily so that certificates will be renewed fully automatically:

I am receiving a daily output via E-Mail like this now:

relayd.conf and smtpd.conf

Besides `httpd`, `relayd` (mainly for Gemini) and `smtpd` (for mail, of course) also use TLS certificates. And as you can see in `acme.sh`, the services are reloaded or restarted (`smtpd` doesn't support reload) whenever a certificate is generated or updated.

Rexification

I didn't write all these configuration files by hand. As a matter of fact, everything is automated with the Rex configuration management system.

https://www.rexify.org

At the top of the `Rexfile` I define all my hosts:

General ACME client configuration

ACME will be installed into the frontend group of hosts. Here, blowfish is the primary, and twofish is the secondary OpenBSD box.

This is my Rex task for the general ACME configuration:

And there is also a Rex task just to run the ACME script remotely:

Furthermore, this snippet (also at the top of the Rexfile) helps to determine whether the current server is the primary server (all hosts will be without the `www.` prefix) or the secondary server (all hosts will be with the `www.` prefix):

The following is the `acme-client.conf.tpl` Rex template file used for the automation. You see that the `www.` prefix isn't sent for the primary server. E.g. `foo.zone` will be served by the primary server (in my case, a server located in Germany) and `www.foo.zone` by the secondary server (in my case, a server located in Japan):

And this is the `acme.sh.tpl`:

Service rexification

These are the Rex tasks setting up `httpd`, `relayd` and `smtpd` services:

This is the `httpd.conf.tpl`:

and this the `relayd.conf.tpl`:

And last but not least, this is the `smtpd.conf.tpl`:

All pieces together

For the complete `Rexfile` example and all the templates, please look at the Git repository:

https://codeberg.org/snonux/conf

Besides ACME, other things, such as DNS servers, are also rexified. The following command will run all the Rex tasks and configure everything on my frontend machines automatically:

The `commons` is a group of tasks I specified which combines a set of common tasks I always want to execute on all frontend machines. This also includes the ACME tasks mentioned in this article!

Conclusion

ACME and Let's Encrypt greatly help reduce recurring manual maintenance work (creating and renewing certificates). Furthermore, all the certificates are free of cost! I love to use OpenBSD and Rex to automate all of this.

OpenBSD suits perfectly here as all the tools are already part of the base installation. But I like underdogs. Rex is not as powerful and popular as other configuration management systems (e.g. Puppet, Chef, SALT or even Ansible). It is more of an underdog, and the community is small.

Why re-inventing the wheel? I love that a `Rexfile` is just a Perl DSL. Also, OpenBSD comes with Perl in the base system. So no new programming language had to be added to my mix for the configuration management system. Also, the `acme.sh` shell script is not a Bash but a standard Bourne shell script, so I didn't have to install an additional shell as OpenBSD does not come with the Bash pre-installed.

E-Mail your comments to `paul@nospam.buetow.org` :-)

Other *BSD related posts are:

2026-04-02 f3s: Kubernetes with FreeBSD - Part 9: GitOps with ArgoCD

2025-12-14 f3s: Kubernetes with FreeBSD - Part 8b: Distributed Tracing with Tempo

2025-12-07 f3s: Kubernetes with FreeBSD - Part 8: Observability

2025-10-02 f3s: Kubernetes with FreeBSD - Part 7: k3s and first pod deployments

2025-07-14 f3s: Kubernetes with FreeBSD - Part 6: Storage

2025-05-11 f3s: Kubernetes with FreeBSD - Part 5: WireGuard mesh network

2025-04-05 f3s: Kubernetes with FreeBSD - Part 4: Rocky Linux Bhyve VMs

2025-02-01 f3s: Kubernetes with FreeBSD - Part 3: Protecting from power cuts

2024-12-03 f3s: Kubernetes with FreeBSD - Part 2: Hardware and base installation

2024-11-17 f3s: Kubernetes with FreeBSD - Part 1: Setting the stage

2024-04-01 KISS high-availability with OpenBSD

2024-01-13 One reason why I love OpenBSD

2022-10-30 Installing DTail on OpenBSD

2022-07-30 Let's Encrypt with OpenBSD and Rex (You are currently reading this)

2016-04-09 Jails and ZFS with Puppet on FreeBSD

Back to the main site