With the recent resolution of issue#2800 that now separates certificate renewals from the new-certificate issuance rate-limit, I would like to more evenly spread-out my renewals that were previously clustered into weekly batches.
So, is there a way to run certbot renew to process perhaps only 3 pending certificate renewals at a time, so that I might invoke certbot renew say every 6hrs and redistribute the renewals more evenly across the week?
As a hack, you could manually edit the configuration files in /etc/letsencrypt/renewal/ and set renew_before_expiry to different values in different files. The default (when it’s not specified) is “30 days”. You could set some to “31 days” or some to “29 days 18 hours” or whatever.
You might also be able to create a few non-renewal configuration files containing just that setting and create different cron jobs using the -c argument to pass different files.
I’d like to keep /etc/letsencrypt/ unmolested so that any outside certbot invokations don’t fall foul of a transient renewal/ folder.
Instead, I’d like to use --config-dir /etc/letsencrypt-alt/ containing symlinks to the /etc/letencrypt/ top-level content, but with a real renewal/ folder containing .conf files for the three most pressing renewals.
Do you see a problem with /etc/letsencrypt-alt/ containing symlinks to the real folders of /etc/letsencrypt/ ?
I think I’ll have my 6hr script temporarily move the excess .conf files to a renewal-save/ folder, invoke certbot renew, then return the excess .conf files to renewal/. This way, if any outside certbot invoke adds any new .conf file(s), they will survive the 6hr process.
You could do something more creative like split up the sorted list of certificates, modulo the number of days in the week.
#!/usr/bin/env bash
ALL_CERTS=$(find /etc/letsencrypt/renewal -type f -printf '%f\n' | sed 's/\.conf//' | sort -h)
TOTAL_TO_RENEW=$(echo "$ALL_CERTS" | wc -l)
TOTAL_PER_BATCH=$(awk "function ceil(x){return x%1 ? int(x)+1 : x} BEGIN {print ceil($TOTAL_TO_RENEW/7)}") # ceil so we dont skip any
TO_SKIP=$(($TOTAL_PER_BATCH * ($(date +%u)-1))) # floor so we dont skip any
THIS_BATCH=$(echo "$ALL_CERTS" | tail -n +$(($TO_SKIP + 1)) | head -n $TOTAL_PER_BATCH)
while read -r CERT; do
echo "Renewing $CERT"
certbot renew --cert-name "$CERT" --non-interactive
done <<< "$THIS_BATCH"
You’d need to double check it, but on each day, it would give a few attempts per day for each group of domains, and you should end up with a bunch of certificates staggered across days-of-week.
You could probably adjust it to 6 hour time intervals but using anything except integers in bash sucks!
(accidentally withdrawn while updating)
For the record, my solution is to run the following every 6hrs:
pushd /etc/letsencrypt/live # change to the live certificates folder
ls -tr1 | head -2 | while read fqdn; do # attempt explicit renewal of the oldest 2 certificates
echo $fqdn
certbot renew -n -q --cert-name $fqdn
done
popd # return to the previous folder
I use dns-01 , though due to the past renewal clustering, I won’t have another certificate to renew until 2019-03-18; however, I’m hoping my auth/cleanup/deploy hooks will run as normal.
Just a tiny comment. Your script shows that you, like many others, aren’t aware that ls defaults to outputting one file per line when the output isn’t a terminal (e.g. when it, like here, is a pipe), the man page on my system doesn’t say it (but it works that way ls | cat is a simple way to test it), but see e.g. the STDOUT section of http://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/ls.html