Recently, I received a notification telling me my SSL certificate is expiring near the end of the month. Thus I have a choice: shell out 90 euros again (wildcard certificate for *johnnei.org) or switch to Let’s Encrypt’s free ones. If you check your browser, you’ll see I’ve chosen the latter.
Now my setup is quite… funky, let’s call it that. At the core, my setup sounds simple. I use Nginx as a reverse proxy for my domains and subdomains. Some are proxied to the PHP FPM daemon, a few to a dedicated application and the rest to Kubernetes. Now you might wonder, why is it difficult? You may have noticed I said domains. I also host johnnei.io on the same host. So even though I have a wildcard certificate, I don’t know which one to serve out until I know which host is requested. Thankfully there is Server Name Indication (SNI) to support this use case. SNI isn’t available on all devices, but anything made after the Windows XP age should be fine. That is more than enough for a personal bloggy thing.
So now you might be thinking: This sounds fairly standard, what’s the problem then? For my ‘development domain’ I didn’t purchase a Comodo certificate. For one subdomain, I did want an SSL connection to an application deployed in Kubernetes. So along with cert-manager, I configured it to retrieve a certificate. As I already handle the SSL-termination in Nginx, I had to extract that certificate from the cluster. As those certificates change quite regularly, I wrote a small cronjob to extract the certificate nightly. So that works fine again, but that’s not all. As the final cherry on top, I have set up GitLab Pages as a fallback in Nginx for when none of the server names match.
So off I went onto the journey to configure Let’s Encrypt certificates. As a bonus, I also looked into splitting up my Nginx configuration file into a file per domain. I remembered a site that helps to configure Nginx with some default settings based on the used technologies, simply called Nginx Config. They also include small config files to trigger https upgrades while integrating with ACME challenges for Let’s Encrypt, and also the commands for Certbot to request the certificates.
With that information, I went to install Certbot on my server and split the first domain into a separate file. To verify the configuration, I invoked a few requests with cURL to see if the HTTPS upgrade is working, if the ACME challenge path doesn’t upgrade to HTTPS and if the final response is still the proxied application. It all seemed fine, so I told Certbot to request my certificate and that all went fine. After that, I swapped out the certificates paths in the subdomain configuration file, and there it was: Let’s Encrypt was live. I repeated this process for the rest of my domains (why do I have so many?). They all went fine. All that is left is to see if the first certificate roll-over works fine.