rset(1) : Formulas

Let's Encrypt on OpenBSD and FreeBSD

The Progressive Label Notation pln(5) allows for initialization of state in one label followed by another label which further acts on this state. Obtaining an certificate is one of many such uses for this pattern, and if no work needs done simply call exit To skip the next script to skip to the next step.

OpenBSD: httpd(8), acme-client(1)

Start by installing two files Where the acme client configuration contains a customized version of /etc/examples/acme-client.conf

To obtain the initial certificate we need a minimal httpd configuration for the challenge that This is a bootstrap stage and will be replaced by a more complete configuration after we have the keys for TLS

server "default" {
    listen on egress port 80

    location "/.well-known/acme-challenge/*" {
        root "/acme"
        root strip 2

types {
    include "/usr/share/misc/mime.types"

Once the cert is generated a subsequent rule can go ahead an replace /etc/httpd.conf with a config that includes the tls keys

# httpd.conf
listen on * tls port 443

tls {
    key "/etc/ssl/private/"
    certificate "/etc/ssl/"

Since PLN files are executed in order, we can use on label to set up a configuration to bootstrap the web server, and a subsequent label to ensure that the final httpd configuration is in place. Finally install a weekly cron task to renew the certificate

# httpd.pln

    [ -f "/etc/ssl/acme/private/privkey.pem" ] && exit
    ./rinstall www/acme-httpd.conf /etc/httpd.conf
    rcctl restart -f httpd
    ./rinstall www/acme-client.conf /etc/acme-client.conf

    ./rinstall vm2/httpd.conf /etc/httpd.conf && rcctl restart httpd

    ./rinstall vm2/weekly.local /etc/weekly.local

FreeBSD: nginx(8), lego(1)

Lego is portable acme client that has served me well. It's a wonderful tool because it starts up it's own web server to reply to the challenge. Once we have obtained a certificate we can continue to use this built-in feature using a simple proxy

# nginx.conf
server {
    listen 80;

    location ^~ /.well-known/acme-challenge/ {
        proxy_set_header Host $host;

As with OpenBSD, we can write the labels PLN configuration in order to sequence the configuration

# httpd.pln

    [ -d /usr/home/gs/www/.lego ] && exit
    lego --email="" --domains --http --http.port :80 run

    ./rinstall www/nginx.conf /usr/local/etc/nginx/nginx.conf && /usr/local/etc/rc.d/nginx restart