Let's Encrypt on OpenBSD
UPDATE: letskencrypt
has been merged into the base system of OpenBSD and renamed to acme-client
When Let's Encrypt has hit the planet and euphoria calmed down, I decided to give it a spin as soon as a clean, secure and simple OpenBSD client would be available. I may be late some months: letskencrypt has been published on Github on May 12th, 2016 and is currently available in version 0.18. I won't go into the merits of "why yet another client". Read Kristaps Dzonsons page on his beautiful design using isolated independent components. No Python. No Ruby. No Bash.
Installation on OpenBSD 5.9-STABLE
Currently, there is no precompiled binary package available for 5.9. However, for OpenBSD 6.0 there will be one. A portable version allows other operating systems to easily port it over. Without digging too much, one can find a Linux and FreeBSD version already. Let's download and compile it manually (no cause for alarm):
$ ftp -o - https://kristaps.bsd.lv/letskencrypt/snapshots/letskencrypt.tgz | tar -zxvf - $ cd letskencrypt-0.18/ $ make && doas make install
Prepare your directory structure. Note: I will be using the -m
flag of letskencrypt which will automagically append the domain name to your paths. This comes in handy if you'd like to structure your directories by domains - mainly for managing multiple domains on one host. Also, I have learned most people tend to store challenge files in .well-known/acme-challenge
of your document root but I couldn't find any 'official' standard proposing that (yet).
# mkdir -p /etc/letsencrypt/my.domain /etc/ssl/letsencrypt/{my.domain,private} # mkdir -p /var/www/letsencrypt/.well-known/acme-challenge/ # chmod 700 /etc/letsencrypt /etc/ssl/letsencrypt/private
nginx
I am using nginx as reverse proxy. The 'real' web servers are hidden behind. Therefore, my nginx needs to be told to serve Let's Encrypt challenge files locally on port 80. If you serve your web site(s) locally it's even easier: Omit the proxy_redirect
parameter. An example for Apache is provided within the letskenrypt man page. Read this explanation on nginx location matches for the mere details.
# Letsencrypt needs http for acme challenges location ^~ /.well-known/acme-challenge/ { proxy_redirect off; default_type "text/plain"; root /var/www/letsencrypt; allow all; }
Get ready to rumble
Once the scene has been set one can pull the trigger. The options -vnN
will create both keys (account and domain) and report output verbosely. Here I do specify the challenge directory manually, as letskenrypt
stores them in /var/www/letsencrypt/
by default.
# letskencrypt -vnN -C /var/www/letsencrypt/.well-known/acme-challenge/ -m my.domain
After some woodoo output you should now see a couple keys created:
# find /etc/letsencrypt/ -ls 13189 4 drwx------ 3 root wheel 512 Jul 13 15:03 /etc/letsencrypt/ 13191 8 -r-------- 1 root wheel 3272 Jul 13 14:05 /etc/letsencrypt/privkey.pem 13194 4 drwxr-xr-x 2 root wheel 512 Jul 13 15:03 /etc/letsencrypt/my.domain 13195 8 -r-------- 1 root wheel 3268 Jul 13 15:03 /etc/letsencrypt/my.domain/privkey.pem # find /etc/ssl/letsencrypt/ -ls 12849 4 drwxr-xr-x 4 root wheel 512 Jul 13 14:54 /etc/ssl/letsencrypt/ 13188 4 drwx------ 3 root wheel 512 Jul 13 14:53 /etc/ssl/letsencrypt/private 13192 4 drwxr-xr-x 2 root wheel 512 Jul 13 14:56 /etc/ssl/letsencrypt/private/my.domain 13193 8 -r-------- 1 root wheel 3272 Jul 13 14:56 /etc/ssl/letsencrypt/private/my.domain/privkey.pem 13190 4 drwxr-xr-x 2 root wheel 512 Jul 13 15:03 /etc/ssl/letsencrypt/my.domain 13196 4 -r--r--r-- 1 root wheel 1647 Jul 13 15:03 /etc/ssl/letsencrypt/my.domain/chain.pem 13197 8 -r--r--r-- 1 root wheel 2139 Jul 13 15:03 /etc/ssl/letsencrypt/my.domain/cert.pem 13198 8 -r--r--r-- 1 root wheel 3786 Jul 13 15:03 /etc/ssl/letsencrypt/my.domain/fullchain.pem
For nginx you'll want to point your ssl_certificate
parameter to the my.domain/fullchain.pem
and naturally, the ssl_certificate_key
to private/my.domain/privkey.pem
. Reload your nginx and your site will serve the new certificates:
# /etc/rc.d/nginx reload
Renewal
Let's Encrypt certificates are valid for 90 days only. Without a fully automated renewal mechanism, you'll waste precious life time. You can always manually check the validity period of your certs:
# letskencrypt -v -C /var/www/letsencrypt/.well-known/acme-challenge/ -m my.domain letskencrypt: /etc/ssl/letsencrypt/my.domain/cert.pem: certificate valid: 89 days left
For automated renewal, add a cron(8)
job. The cert.pem
file will be checked for its expiration on every cron run. letskencrypt(1)
will only attempt to refresh the signature if the remaining validity period is less than 30 days.
# Update Lets Encrypt certificate(s) 0 2 * * * letskencrypt -C /var/www/letsencrypt/.well-known/acme-challenge/ -m my.domain
Revocation
Even though the short certificate life time reduces the attack surface, key compromises need to be treated urgently. letskencrypt
will revoke your certs using the -r
option. I haven't tested this myself yet, for obvious reasons. :)
:wq
Comments
Remember that letskencrypt returns exit code 2 if the keys weren't updated--cron might take that as an error. If the exit code is zero, then the certificates were updated and you should reload the web server. (Or does nginx automatically pick up new certs?)
Actually there IS precompiled binary package available for 5.9, right?
pkg_add letsencrypt
Link to the package: ftp://ftp2.fr.openbsd.org/pub/OpenB...
Hi Özgür, the package you refer to is 'letsencrypt' not 'letskencrypt' (note the k), which is a different client.
Cheers, Stephan