[HOWTO] Automatic Certificate Renewal with Let's Encrypt and DNS Auth

Status
Not open for further replies.

stitch

Dabbler
Joined
Jan 7, 2017
Messages
24
This is based on the earlier work of airflow in this thread. Because of the security concerns with exposing your NAS to the whole world even if only via jail, the better and more secure option is to use DNS verification.

The Acme.sh script by neilpang gives you Let's Encrypt certificate generation and supports performing DNS verification (with the option to automatically update your personal domain's DNS provider via API-where available) to verify you own the DNS and that they can issue the certificate.

So, this is a little involved but I believe it would survive any updates to FreeNAS. I've done this entirely on FreeNAS 11.1 via a combination of SSH and the new GUI. You can probably do it via the Shell menu too.

Step 1. Get a certificate onto the system
Basically, you need to get a certificate that FreeNAS will allow for use as an HTTPS certificate so that there is an entry in the configuration that we can "pretend to be". In my case, I created a CA, then generated the certificate from there.

Step 2. Set up an iocage jail and call it "acme".

Step 3. Ensure that you configure your jail with an IPv4 address, e.g. if using a LAGG, it would read "LAGG0|172.16.10.26" (without the quotes of course).

Step 4. Stop and start the jail

Step 5. Via SSH, once in type the following
iocage console acme

Step 6. Verify that your jail does have an IP using the ifconfig command

Step 7. Install pkg
pkg

Step 8. Install the packages we need to complete the rest (I apologize, I like vim)
pkg install curl bash vim

Step 9. Swap over to bash
bash

Step 10. Download and install acme
curl https://get.acme.sh | sh

Step 11. Modify the first line of the resulting bash script that was downloaded to use the jail's bash
Code:
#!/bin/bash
# is replaced with
#!/usr/local/bin/bash


Step 12. Export your Dynamic DNS API credentials based on the instructions here. I'm assuming you are using one of the support APIs.

Step 12. Generate your certificates
.acme.sh/acme.sh --issue --dns dns_aws -d myhost.mydomain.com

Step 13. Exit the jail
exit

Step 14. Make a directory on one of your storage volumes for your certificates to be symbolicly linked. Basically, we're going to create symbolic links in a future step to match the naming of the certificate we generated in step 1.
mkdir /mnt/myvolumename/certs

Step 15. Determine the names of the certificates we created in step 1 so we know what to name our symbolic links
ls /etc/certificates

Step 16. Create our symbolic links to our generated certificates

ln -s /mnt/iocage/jails/acme/root/root/.acme.sh/myhost.mydomain.com/fullchain.cer /mnt/myvolumename/certs/myhost.crt
ln -s /mnt/iocage/jails/acme/root/root/.acme.sh/myhost.mydomain.com/myhost.mydomain.com.key /mnt/myvolumename/certs/myhost.key


Step 17. Get your GUI on- Log into your FreeNAS server's UI
Step 17a. Set your tunable
Go to System -> Tunables -> Click "Add Tunable". Set the Variable to "SSLDIR" without quotes. Set the Value to "/mnt/myvolumename/certs/" without quotes. Please make sure it is set to enabled.

Step 17b. HTTPS
Go to System -> General -> GUI Protocol and set it HTTP+HTTPS. Set the Certificate to the one you created in step 1.
FOR THE LOVE OF ALL THAT IS GOOD: WebGUI HTTP -> HTTPS Redirect SHOULD BE UNCHECKED!!

Step 17c. CRON Task to restart
Go to Tasks -> Cron Jobs
Users: Root
Command: service nginx restart
Set the Minute to Each Selected and choose 5
Set the Hour to Each Selected and choose 0
Set the Day of the Month to Each Selected and 1
Set the Month to each month
Do not set day of the week
Hit Save

Step 18. Go back to SSH and console into the jail again
iocage console acme

Step 19. Set your crontab to renew the certificate each month
crontab -e
Paste in the following:
Code:
0 0 1 * *  /root/.acme.sh/acme.sh --renew --force -d myhost.mydomain.com

This will renew the certificate on the 1st day of each month

Step 20. Exit the jail
exit

Step 21. Restart Nginx
service nginx restart

That should be it I think?
 
Last edited:

danb35

Hall of Famer
Joined
Aug 16, 2011
Messages
15,504
...or you could use this, which works through the API so that everything's peachy with the config database and middleware.
 

danb35

Hall of Famer
Joined
Aug 16, 2011
Messages
15,504
0 0 1 * * /root/.acme.sh/acme.sh --renew --force -d myhost.mydomain.com
Regardless of whether you update the cert using these instructions or my script, this just isn't a good way to do the renewal, for a few reasons:
  • It runs the renewal exactly at midnight, at the same time that all the other misconfigured cronjobs are doing it and therefore Let's Encrypt server load is highest.
  • It only runs once a month. If it fails a couple of times (maybe because the LE servers are overloaded, or network problems on your end, or Cloudflare's being silly, or...), your cert's going to expire.
  • Assuming it does successfully renew, it renews more often than necessary. This doesn't really hurt anything, but there's simply no reason for a new cert every month.
A better way to run the cron job would be this:
Code:
7 5 * * * /root/.acme.sh/acme.sh --cron

This will run daily at 5:07 AM (pick some other random time if you like). acme.sh will check any existing certs, and if any have less than 30 days' validity remaining, it will (attempt to) renew them. If it fails, it will try again the next day, then the next, etc.
 

stitch

Dabbler
Joined
Jan 7, 2017
Messages
24
Hey @danb35, I stand corrected, I threw this together during some very late nights trying to get Let's Encrypt going and didn't have the time to do a very good job (it seemed like a good idea at the time). I whole heartedly agreethe linked script looks better (and didn't exist when I wrote this post). So for anyone who stumbles across this post, you should check out the linked method as it is oodles better!
 

danb35

Hall of Famer
Joined
Aug 16, 2011
Messages
15,504
No, the script wasn't out when you write this, and I'm not sure the API methods were there anyway. Always more than one way to skin a cat, but something that runs through the API seems safer.
 
Status
Not open for further replies.
Top