Get a SSL certificate

SSL certificates allow to make TLS encryption and thus, in other things, serve your website through the more secure protocol HTTPS.

It is necessary when sensitive data is sent to/from your server.

Letsencrypt

"Let's Encrypt" is a free certificate authority providing easy to use API to get and manage certificates.

There is a client included in OpenBSD names "acme-client" to deal with such tasks. It currently requires a http server to generate certificates. That's why we'll discuss acme-client here. However, you certainly can use those certificates for other needs that https such as IMAPS.

⚠ First of all, check you opened port 80 in the firewall and eventually in your router. Acme-client needs to check for some files you'll make available for letsencrypt with httpd.

Actually, acme-client will ensure you manage the domain you request a certificate for. To do so, it ask an unique file to Let's Encrypt, kinda fingerprint, stored in "/var/www/acme". Then, Let's Encrypt try to get this "secret" file on your server at ".well-known/acme-challenge", asking for "http://athome.tld/.well-known/acme-challenge/secret_file". If it succeeds, the request is accepted and you get a certificate. Finally the file is deleted.

Remember your website is probably located in "/var/www/htdocs/website" or something. You need to make "/var/www/acme" for letsencrypt to get the secret file. So, add a "location" instruction in "/etc/httpd.conf" :

server "athome.tld" {
    listen on * port 80
    location "/.well-known/acme-challenge/*" {
        root "/acme"
        request strip 2
    }
    root "/htdocs/website"
}

A few explanations :

⚠ This section will have to be added for every domain served by httpd, even alternative names specified in the acme-client configuration file below. You might find easier to use "include" instruction in "httpd.conf" later as it is described in the "Tips" part a bit further 😉.

Before calling acme-client, you must configure it by editing "/etc/acme-client.conf". You can use "/etc/examples/acme-client.conf" as template.

For the example, the file might look like this :

authority letsencrypt {
  api url "https://acme-v02.api.letsencrypt.org/directory"
  account key "/etc/acme/letsencrypt-privkey.pem"
}
authority letsencrypt-staging {
  api url "https://acme-staging-v02.api.letsencrypt.org/directory"
  account key "/etc/acme/letsencrypt-staging-privkey.pem"
}
domain athome.tld {
    alternative names { webmail.athome.tld www.athome.tld }
    domain key "/etc/ssl/private/athome.tld.key"
    domain full chain certificate "/etc/ssl/athome.tld.crt"
    sign with letsencrypt
}

Of course, replace "athome.tld", "alternative names { ..." with the other domains and subdomains you need and eventually the location of key and full chain certificate.

Make sure necessary directories are here (they might already exist) :

# mkdir -p -m 700 /etc/ssl/private
# mkdir -p -m 755 /var/www/acme

Check acme-client configuration with "# acme-client -n", it must return nothing.

Now you can get your certificates :

# acme-client -v athome.tld

At first, you might want to make sure everything works as expected using "sign with letsencrypt-staging" in "/etc/acme-client.conf" and switch back to "sign with letsencrypt" later. You can force getting certificates using "acme-client -F athome.tld".

Consider renewing certificates automatically using "/etc/weekly.local" file. It is a script executed every week.

/usr/sbin/acme-client -v athome.tld && /usr/sbin/rcctl reload httpd

Using "&&" make httpd to reload certificates only if there are renewed certificates. If at some point other daemons than httpd uses your certificates, you'll have to reload them too (relayd, dovecot...)

Now you've got a certificate, let's enable https in "/etc/httpd.conf" 😄. A new section "tls" appears. :

server "athome.tld" {
	listen on * port 80
	# http version
	# [...snip...]
}
# extrait de /etc/httpd.conf
server "athome.tld" {
    listen on * tls port 443
    root "/htdocs/website"
    tls {
        certificate "/etc/ssl/athome.tld.crt"
        key "/etc/ssl/private/athome.tld.key"
    }
    hsts
    # add your website specific configuration here
}

As you can see, now httpd listen on the port 443 (https) : remember to configure your firewall for this.

You might want to redirect clients accessing from http to https. To do so, add an instruction matching all request ("location *"). The clients will be redirected to the https version except if the request matched the previous one for acme-client.

# extrait de /etc/httpd.conf
server "athome.tld" {
    listen on * port 80
    location "/.well-known/acme-challenge/*" {
        root "/acme"
        request strip 2
    }
    location * { block return 301 "https://$SERVER_NAME$REQUEST_URI" }
}
server "athome.tld" {
    listen on * tls port 443
	#[...]

Remember to add such section for every website you want to serve. You may want to use "include" instructions to ease your life. See next part 😉.

About "include" usage

You will certainly enable tls for multiple website. Instead of rewrite the same instructions again and again, you can include a file.

First, create a directory to keep multiple httpd configuration files :

# mkdir /etc/httpd.d

Then, we create "/etc/httpd.d/acme.conf" file to keep instructions related to acme seen earlier :

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

You even can go a bit further by creating a file "/etc/httpd.d/tls.conf" for multiples lines about certificates :

tls {
    certificate "/etc/ssl/athome.tld.crt"
    key "/etc/ssl/private/athome.tld.key"
}
hsts

Now, the file "/etc/httpd.conf" can be simplified to those lines below. The whole file let you serve 3 websites : athome.tld, www.athome.tld and webmail.athome.tld :

server "www.athome.tld" {
    listen on * tls port 443
    include "/etc/httpd.d/tls.conf"
    root "/htdocs/www.athome.tld"
}
server "www.athome.tld" {
    listen on * port 80
    include "/etc/httpd.d/acme.conf"
    location * { block return 301 "https://$SERVER_NAME$REQUEST_URI" }
}
server "athome.tld" {
    listen on * tls port 443
    include "/etc/httpd.d/tls.conf"
    block return 301 "https://www.$SERVER_NAME$REQUEST_URI"
}
server "athome.tld" {
    listen on * port 80
    include "/etc/httpd.d/acme.conf"
    location * { block return 301 "https://$SERVER_NAME$REQUEST_URI" }
}
server "webmail.athome.tld" {
    listen on * tls port 443
    include "/etc/httpd.d/tls.conf"
    root "/htdocs/webmail.athome.tld"
}
server "webmail.athome.tld" {
    listen on * port 80
    include "/etc/httpd.d/acme.conf"
    location * { block return 301 "https://$SERVER_NAME$REQUEST_URI" }
}

The above configuration redirect from athome.tld to www.athome.tld. Another website webmail.chez.tld is handled. For each domain, using acme is possible.

You may have noticed each section is quite a routine. You can imagine other usages to "include" instruction if you need it.

Thank you Grégory Marchal for your suggestions on this part. 😉

Facultative : CAA records

You can add a CAA record in your DNS zone to show you own the domain and YOU asked a certificate to Let's Encrypt. This is just a proof of honesty helping someone to trust the certificate used.

@ 300 IN   CAA   0 issue "letsencrypt.org"

Generate a self-signed certificate

You can generate your own self signed-certificate. At first connection, clients will see a warning asking if they trust or not the certificate.

To do so, see man 8 ssl in section "Generating RSA server certificates".

Check your server SSL configuration

Find below a few tools to check how well you've configured your server (not only https) :

https://www.ssllabs.com/

https://tls.imirhil.fr/

https://observatory.mozilla.org/