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 - | 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


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


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


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. :)