Automating Let's Encrypt Certificate Renewal on Windows with Crypt-LE

Encryption fun
Photo by Mauro Sbicego / Unsplash

Let's Encrypt certificate renewal automation is super simple and almost automatic on Linux.  Cerbot and plugins for applications pretty much take care of everything for you.

Not so on Windows.  There are now several Windows Clients that will do the certificate requests (I'm using Crypt-LE https://github.com/do-know/Crypt-LE/releases ) including some that have basic renewal automation built in - but I need to do more.  I have three services that rely on certificates (Nginx, hMailServer, and fTelnet) - all need to be restarted to pick up the new certificate.  Additionally, fTelnet needs the certificate converted to .pfx format to work.  Merely renewing is not enough.

PowerShell (and Windows Task Scheduler) to the rescue.  You need to create a .ps1 powershell script file - first thing is to add the line to renew the cert, which is exactly like the command to generate the cert with --renew x (where x is number of days before expiration) on the end.  Mine looks kind-of like this:

💡
le64.exe -email "tom@kn6q.org" -key account.key -csr domain.csr -csr-key web.key -crt web.cer -domains "kn6q.org,www.kn6q.org,mail.kn6q.org,plex.kn6q.org,bbs.kn6q.org" -generate-missing --path C:\html\.well-known\acme-challenge -live -log-config log.conf --renew 60

I'm picking up my existing account key and csr, telling it to put the challenge files on the webserver and setting up a log with the -log-config so that it doesn't just print to the screen what happens.  Next I need to convert my new cert to pkcs12 format for fTelnet.  I have OpenSSL installed to do that, I need to run a command like this:

💡
openssl pkcs12 -export -in web.cer -inkey web.key -out web.pfx -password pass:mypassword

It picks up my new cert and key and converts it to .pfx file with the password of mypassword

Now we need to restart services.  Powershell can do that, so I have a command like this for Nginx, hMailServer and fTelnetProxy in there:

💡
Restart-Service Nginx -PassThru | Out-File lelog.txt -Append -NoClobber -Encoding utf8

I'm restarting my service and appending my log from Crypt-Le with the status.  Now that we have a script we save it to a file named something like "renewcert.ps1".  From PowerShell, you can run your script make sure it is working the way that you want and your log file looks the way you want (note I specified in PowerShell to write to the log file in utf8 format, because this is what Crypt-Le is using and I'm appending to the same file).

Next we just need to schedule our new PowerShell Script to run periodically with Task Scheduler:

Under Actions we want to run PowerShell:

💡
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

And we want to add an argument to run our new (non-signed) script:

💡
-ExecutionPolicy Bypass -File renewcert.ps1

You also need to tick the box on the General tab to run with the highest privileges in order to have admin privileges to reset your services.

For the Trigger, you can schedule your script run every night or every week - but it's going to restart your services whether or not you have a new Cert.  It's possible to restart them conditionally on a new certificate being issued, but that's another layer of complexity I didn't get into because I don't mind periodically restarting these services.