· All Posts · All in OpenBSD · All in Server

OpenBSD Web Server with httpd and Let's Encrypt

Before starting with the acme-client and the httpd setup, I had created a Let’s Encrypt account with a registered account key.

Httpd config

add to /etc/httpd.conf the domain or default section the challenge path that is going to get hit for the certificate

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

and restart httpd

doas rcctl restart httpd

Acme client

Then configure the acme client

doas vi /etc/acme-client.conf
authority letsencrypt {
        api url $api_url
        account key "/etc/acme/letsencrypt.pem"
domain {
    alternative names { }
    domain key "/etc/ssl/private/"
    domain full chain certificate "/etc/ssl/"
    sign with letsencrypt

Try to get the certificate

doas acme-client -v

If everything worked you should see the command terminate with

acme-client: /etc/ssl/ created


we then update the /etc/httpd.conf for the TLS key pair and redirect port 80 to https port 443:


server "" {
    alias ""
    listen on $ext_ip port 80
    block return 301 "https://$SERVER_NAME$REQUEST_URI"

server "" {
    alias ""
    listen on $ext_ip tls port 443
    tls {
      certificate "/etc/ssl/"
      key "/etc/ssl/private/"
    log style combined
    root "/htdocs/"
    location "/.well-known/acme-challenge/*" {
        root "/acme"
        request strip 2
        directory no auto index

#server "" {
#    listen on $ext_ip port 80
#    root "/htdocs/"
#    location "/.well-known/acme-challenge/*" {
#      root "/acme"
#      request strip 2
#        directory no auto index
#    }

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

to test the configuration without stopping httpd (no downtime!) we can run

doas httpd -n

If that works, restart httpd and we should now have https available

See the recent post on a simple web analytics dashboard with GoAccess for httpd log based, server side analytics.


We utilize periodic system maintenance daily which runs the user script /etc/daily.local, if it exists.

doas vi /etc/daily.local

acme-client -v
rcctl reload httpd

and make it executable

doas chmod +x /etc/daily.local

The certificate is valid for 90 days, so it’ll not do anything immediately but only renew it closer to expiration.


If your certificate doesn’t renew you will get emailed by Let’s Encrypt two weeks before expiry. It is best to just run the acme-client manually to diagnose the problem. I recently was messing with my keys and ran into the following issue.

acme-client -v
api_url = ""
acme-client: /etc/ssl/private/ group read/writable or world read/writable
chmod g-r /etc/ssl/private/

SSL Labs

The SSL Server test performs an analysis of our server configuration, supported protocols, weak ciphers and its susceptibility to downgrade attacks. Our setup of OpenBSD httpd, libressl with Let’s Encrypt effortlessly scores an A+ on SSL Labs.

SSL Labs A+ score for

And thereby made the top list too.

SSL Labs recent top ranked servers

DNS Certification Authority Authorization (CAA)

CAA DNS record allows to specify one or more Certification Authorities (CAs) to issue certificates for a given domain. CAA is specified in RFC6844 to improve of the public key infrastructure (PKI). Without CAA, any CA can issue a certificate for any domain name.

We can set a CAA via a DNS record called CAA (type 257) and restrict certificate issuance. For example, my CAA configuration for Let’s Encrypt is as follows:

@ 10800 IN CAA 128 issue ""

CAs are expected to check this record and refuse issuance should they not find themselves on the whitelist.

Published on Friday, Jul 2, 2021. Last modified on Thursday, Mar 10, 2022.
Go back

If you’d like to support me, follow me on Twitter or buy me a coffee. Use Bitcoin
BTC address: bc1q6zjzekdjhp44aws36hdavzc5hhf9p9xnx9j7cv