OpenBSD httpd TLS Certificate
Migrating OpenBSD httpd from HTTP to HTTPS
LetsEncrypt offer free TLS certs and have a nice ACME clients to handle auto-renewal. Here’s how to implement on OpenBSD, assuming you have your httpd server up and running on port 80 already.
For example you might have some basic /etc/httpd:
types { include "/usr/share/misc/mime.types" }
server "ndonaghy.com" {
listen on * port 80
root "/htdocs"
location "/stuff/*" {
directory {
auto index
}
}
}
Step 1: Add acme-challenge location#
Add this location directive to /etc/httpd.conf:
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
Restart httpd with rcctl restart httpd.
Step 2: Configure acme-client - /etc/acme-client.conf#
Copy the example .conf and replace example.com with your domain and save the file:
cp /etc/examples/acme-client.conf /etc/acme-client.conf
# nano /etc/acme-client.conf
domain example.com {
alternative names { secure.example.com }
domain key "/etc/ssl/private/example.com.key"
domain full chain certificate "/etc/ssl/example.com.fullchain.pem"
Step 3: Run acme-client and fetch key/cert#
Issue this:
acme-client -v yourdomain.com
You should see your key and cert were written; now httpd can use them. Example output:
# acme-client -v ndonaghy.com
acme-client: /etc/ssl/private/ndonaghy.com.key: generated RSA domain key
acme-client: https://acme-v02.api.letsencrypt.org/directory: directories
acme-client: acme-v02.api.letsencrypt.org: DNS: 172.65.32.248
acme-client: account key: https://acme-v02.api.letsencrypt.org/acme/acct/1234******
acme-client: https://acme-v02.api.letsencrypt.org/acme/finalize/1234******/987*********: certificate
acme-client: order.status 3
acme-client: https://acme-v02.api.letsencrypt.org/acme/cert/0123456789abcdef: certificate
acme-client: /etc/ssl/ndonaghy.com.fullchain.pem: created
Step 4: Update firewall - /etc/pf.conf#
Where you are accepting port 80, now add 443:
pass in proto tcp to port { 80 443 } keep state
Step 5: Update httpd - /etc/httpd.conf#
Add HTTPS section to bottom of the file:
server "ndonaghy.com" {
listen on * tls port 443
tls {
certificate "/etc/ssl/ndonaghy.com.fullchain.pem"
key "/etc/ssl/private/ndonaghy.com.key"
}
root "/htdocs"
}
Step 6: Restart httpd and pf#
Like so:
rcctl restart httpd
pf -f /etc/pf.conf
Step 7: Test!#
Can you navigate to https://yourdomain.com?
If not, retrace steps and check acme-client -v output for any errors. Ensure that acme-client.conf, httpd.conf, and pf.conf are configured correctly, no typos, files exist, etc.
Step 8: Enable auto-renewal#
Without autorenewal, you will have a bad time. Here we run once a day and reload httpd if the certificate renewed; && means execute if acme-client return status was 0; if the certificate did not need renewal or failed to renew for some reason, it won’t reload httpd.
# crontab -e
~ ~ * * * acme-client yourdomain.com && rcctl reload httpd
Step 9: Tidy up httpd - /etc/httpd.conf#
Two things to do in HTTP section:
- Add a redirect so all HTTP requests are redirected to HTTPS:
location * {
block return 301 "https://$HTTP_HOST$REQUEST_URI"
}
- Remove
root /htdocsline; we won’t be serving the site from HTTP anymore.
When done, your full /etc/httpd.conf should look something like:
types { include "/usr/share/misc/mime.types" }
server "ndonaghy.com" {
listen on * port 80
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
location * {
block return 301 "https://$HTTP_HOST$REQUEST_URI"
}
}
server "ndonaghy.com" {
listen on * tls port 443
tls {
certificate "/etc/ssl/ndonaghy.com.fullchain.pem"
key "/etc/ssl/private/ndonaghy.com.key"
}
root "/htdocs"
}
Step 10: Accept HTTP#
In case you were wondering:
- The other verification option is DNS TXT record based, but acme-client on OpenBSD does not support this.
- In my case, my DNS provider does not support this; but yours might.
- If you do use DNS TXT verification you need to handle the challenge/response -> DNS update -> DNS propagation aspects, and not with OpenBSD
acme-client.