For quite some time now i have been using letsencrypt certificates for virtually any certificate need.
Given that I manage several separate servers, some of which hosts 50+ sites, managing the certificates needs to be streamlined.
One first thing that i streamlined was the use of a single apache config location that allows me to validate the certificate with Letsencrypt. To understand what i mean let’s go quickly through the process of creating a certificate for a site.
Getting a certificate the “normal” way, using the command line
So i have a site, let’s say http://hellobetty.com (this is a real site of my friends, a great band!) we are just using it as an example right now. It’s time to add https to it.
The first thing i would do is to request a certificate, we will skip the installation of ‘certbot’, the script that allows you to request and obtain a certificate. In any event you can lookup how to install it in your specific environment.
Note that ether are plugins for certbot to automatically install certificates that manipulate your config files (at least for apache and nginx, and probably for other software as well). I don’t really like to not be in control of the changes that happen in my config files, so i don’t use these plugins.
The command would look something like this:
# certbot certonly --webroot -w /home/hellobetty/public_html/ -d hellobetty.com -d www.hellobetty.com
The first parameter “certonly” just instructs certbot that i’m here to manually obtain a certificate. ‘–webroot’ tells certbot that i want to use the ‘web root’ validation method (more about it later). The ‘-w’ tells certbot where is the site ‘root directory’ the two ‘-d’ parameters define which domains should this certificate be connected to.
From that command, certbot would ask you a few questions, then generate and copy a specific file under the website root directory and under a specific directory, which is ‘/.well-known/acme-challenge/’ where the first slash is the website root directory.
A bot from the letsencrypt side of things will then verify it can load this file from the web, and consequently confirm that you control the website. At which point it can issue the certificate.
The potential issues with this process
As you might have already guessed there are a number of challenges that might need to be overcome setting up the certificate this way.
A few examples of these challenges are: your apache config files might have instructions that prevent files or folders that start with a period form being served; your apache config might “capture” all request and route them through a specific file; or your config might allow only certain file types to be served.
In any event as you can see there are multiple potential issues, all with a solution, that might arise. Also, if you are like me, i would not want random files and folders to be written in the top directory of my site (or anywhere under it).
A good solution to all of these problems is to have one single set of configurations that will apply to any website running under that server. There are a number of solutions that people have come up with, most (if not all) rely on the use of the ‘Alias’ command and capture all request to the directory ‘.well-known/acme-challenge/’sending it to a specific folder, not under the actual site structure.
The solution i’m using
As i stated there are many people that came up with similar solutions to these problems, here is what i do, specifically under Apache 2.4.x and under FreeBSD. The specificity of using FreeBSD only applies to the default location of files. (For example, under most linux machines the certificates generated by letsencrypt are stored under a ‘/etc/letsencypt/’, on FreeBSD under ‘/usr/local/etc/letsencrypt/’). If you don’t use FreeBSD you should be able to adapt this solution to your specific file structure.
The first thing i create a new directory ‘/usr/local/etc/letsencrypt/acme-challenge/’.
Then i create a config file that will be loaded first by apache. I call it ‘0000_letsencrypt.conf’ and i store it under ‘/usr/local/etc/apache24/Includes/’ which is where my httpd.conf file is looking for any file ending in “.conf’ and loading it.
The content of the file looks like this:
<Directory "/usr/local/etc/letsencrypt/acme-challenge/">
Options None
AllowOverride None
Require all granted
Header add Content-Type text/plain
</Directory>
Alias /.well-known/acme-challenge/ /usr/local/etc/letsencrypt/acme-challenge/.well-known/acme-challenge/
Now i can make this request:
# certbot certonly --webroot -w /usr/local/etc/letsencrypt/acme-challenge/ -d hellobetty.com -d www.hellobetty.com
The files that letsencrypt uses for verification are written under ‘/usr/local/etc/letsencrypt/acme-challenge/’ but served as if they were under the root directory of any website hosted on this specific server.