Let’s Encrypt on my Raspberry Pi

Some months ago I had created some certs on my Pi via Let’s Encrypt. I forgot to blog about it and today when I wanted to generate some more certs my mind drew a blank. :) I know I had done something in the past as I could see the certs, but I have absolutely no memory of doing it. That’s the problem when you don’t make a blog entry coz then you have nothing to go back and refer to.

In fact, searching my blog for this today I realized that I had generated some Let’s Encrypt certs for work couple of years ago via PowerShell. When I read the blog post I remembered what I had done, but I had completely forgotten about it.

Anyhoo. Let’s Encrypt. Uses the ACME Protocol. There are many clients that can talk this protocol (I alluded it earlier in the case of OpenBSD which comes with a client of its own). The official client is called certbot. If you go to the certbot website to download it it recommends installing Snap and going that route (yes, even for something like Debian Buster which does not have Snap in-built). Why?! I remember finding an alternative last time around and I came across it again today. Hidden in the docs is a section on how to get it via non-Snap methods, and they have a Debian package too for Buster and above (else install Backports to get it).

Cool, so that’s that. Next step is to decide how you want to get certs. Back when I did it on OpenBSD it was for a public website so things were slightly easy in that their ACME client could automate things as it knows OpenBSD’s web-server, and it is a publicly available name, so things were smoother.

At home though what I want is to generate certs for each of my machines. The certbot client has plugins for Apache and Nginx but I can’t use them coz my home machines don’t have any public IP. I suppose I could just generate the certs on one machine and copy them around etc. but I want to keep things simple and automatic. In my case the solution would be to use one of their DNS plugins. They support the following:

  • certbot-dns-cloudflare
  • certbot-dns-cloudxns
  • certbot-dns-digitalocean
  • certbot-dns-dnsimple
  • certbot-dns-dnsmadeeasy
  • certbot-dns-gehirn
  • certbot-dns-google
  • certbot-dns-linode
  • certbot-dns-luadns
  • certbot-dns-nsone
  • certbot-dns-ovh
  • certbot-dns-rfc2136
  • certbot-dns-route53
  • certbot-dns-sakuracloud

Hmm. Step 1, my home DNS zone is a fake one like rakhesh.home so time to get a public one. Step 2, choose one of the providers above I can programmatically access to create DNS records for the ACME verification.

I’ll go with the name raxnet.uk and host it on Route 53. Here’s the documentation for the route53 plugin. The plugin needs to be installed separately; I searched for it in apt and found it as python3-certbot-dns-route53. Instructions to use it are simple and found on their GitHub site and docs.

I created the zone on Route 53 and noted its Zone ID. Next I created a policy in IAM based on the sample offered in the plugin docs (when in the policy screen select JSON and put this in):

The policy allows whoever it is applied to to list my zones and also change resource records specifically for the new zone I created (that’s where the Z00811912W0CAEB6R0R0M Zone ID comes in).

I then created a user in IAM. Let’s call it pi1-certbot as I’ll be using this on that particular device and I’d like to have a separate account per device. Tick the option for programmatic access, and leave the console access unticked. I attached the policy I created above to this user and in the final step was given my access keys. You can place these keys in a folder in ~/.aws/config, but I went with making a new file called /etc/pi1-certbot-awskey:

I also changed this file to be not read/ writeable by anyone else except root.

Next step is to do the certificate request via certbot. I made a script for this so I can reuse:

I placed this in /opt. Feel free to place this wherever. This script takes two arguments – one is the credentials file I created above, other is the domain name to create a cert for.

I’d want this to be renewed automatically so I added this to my root’s crontab via sudo crontab -e:

And that’s it. Now I have certs for this host.

Update: I added a -q switch to the command line in my script so there’s no output. Useful since I am adding it as a crontab entry. I am not showing the modification above just wanted to mention for completeness.

Update 2: I made a variant of the above that also copies the certs over. Remember I said I had done this work some months ago? That was for adding certs to some websites hosted internally using Caddy. I couldn’t use Caddy to get certs as the servers weren’t public so I used Let’s Encrypt with Route53 verification. The following variant copies over any updated files to the Caddy certs folder and also restart Caddy so it picks up the new certs.