Hook for automating certbot (formally known as letsencrypt) certificate renwal or creation using DNS-01 challenges with Epik.
I use the DNS-01
challenge method with certbot
to validate my domains because port 80 is blocked by my ISP.
My DNS is hosted on Epik, and I hadn't found a hook for it yet. So I found one written for NodeJS by Daniel Hopkirk for Cloudflare
that I modified for use with Epik's API.
You'll need to get your Epik API signature by adding an IP address from which
you'll use this script. This will be used to query, modify, and remove the DNS TXT records for your domains being used with certbot
.
This script has been tested with the following key versions:
- Microsoft Windows 10 21H1 (10.0.19043.1165)
- certbot 1.18.0
- node v16.8.0
- npm 7.21.1
cd /
mkdir certbot-epik-dns-hook
cd certbot-epik-dns-hook
git clone https://github.com/AnthonyANI/certbot-epik-dns-hook.git hook
cd hook
npm ci
You'll need to install a version of the dig
command and add it to PATH
for use on Windows. Otherwise the script fails when validating DNS records by using dig-dns-node
.
Follow the instructions here to download and perform a "tools only" install of BIND and add it to PATH
.
Make sure you restart your terminal so your
PATH
is reloaded after addingdig
.
Configuration of this script is done with environment variables. Such variables should be set in a permissions-restricted file .env
in the parent directory of the directory for the hook script (certbot-epik-dns-hook/../.env
), up one level so that it stays outside
of the git repo.
The mandatory variable EPIK_SIGNATURE
should be set to your Epik API signature.
EPIK_SIGNATURE=xxxx-xxxx-xxxx-xxxx
The following variables may be specified in your .env
file also:
DEBUG
Options: true
or false
Default: false
Set this to true to see a bunch more debug information including the results of calls to Epik API and the DNS DIG validation response.
Example:
DEBUG=true
CERTBOT_DNS
Options: Any IP address or domain name of a NameServer you can query
Default: ns3.epik.com
Letsencrypt may validate against the authoritative NS for your domain. By default ns3.epik.com
is used as the most likely candidate.
Use this to set the NS you wish to use instead.
This is used for the script to validate its changes as live at the NS it queries, but it's not guaranteed that this means Letsencrypt will see the same value or control which server it queries. DNS caching and other factors may impact results.
Example:
CERTBOT_DNS=8.8.8.8
CERTBOT_HOST
Options: Subdomain of the domain for which the cert is being retrieved where the validation string will be stored
Default: _acme-challenge
This is where
certbot
says to store a TXT record by default. However, it can be configured for the script alone here should that change via this.env
variable.
Example:
CERTBOT_HOST=certbotchallenge
CLEANUP_ALL
Options: true
or false
Default: false
Set this to true to instruct the cleanup script to remove all challenge TXT records rather than only those used by certbot
each time.
Example:
CLEANUP_ALL=true
To carry out domain certificate renewal, such domains need not be respecified as certbot
keeps track of them
and the settings that it created and will renew as required (unless you force it, it will not renew a certificate that
isn't close enough to expiry so it is safe to automate without concern for timing it to run only months or so apart).
Remove
--dry-run
when you're ready and it's working
If the script appears to hang, wait at least five minutes for it to continue. Validation of the new DNS records may have
initially failed. The script will then wait for DNS records to expire in cache before it attempts to validate them again
and allow certbot
to continue. DNS records generally cache for a time-to-live (ttl) of 300 seconds (5 minutes).
certbot renew --manual --manual-auth-hook "node.exe /certbot-epik-dns-hook/hook/auth_hook.js" --manual-cleanup-hook "node.exe /certbot-epik-dns-hook/hook/cleanup_hook.js" --dry-run
Saving debug log to C:\Certbot\log\letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing C:\Certbot\renewal\example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simulating renewal of an existing certificate for example.com and *.example.com
Hook '--manual-auth-hook' for example.com ran with output:
/------------------- AUTH HOOK START -------------------/
Adding new challenge Resource Record...
/-------------------- AUTH HOOK END --------------------/
Hook '--manual-auth-hook' for example.com ran with error output:
Error: Request failed with status code 400
Bad request. It's possible that the TXT record already exists if debugging. Please run the cleanup script first.
Hook '--manual-auth-hook' for example.com ran with output:
/------------------- AUTH HOOK START -------------------/
Adding new challenge Resource Record...
Validating challenge Resource Record...
WARNING: No DNS TXT answers received.
If this persists, DNS caching may be the cause.
If so and all retries fail, wait and try again later.
Waiting 310 seconds, then retrying up to 2 more time(s)...
Validating challenge Resource Record...
Challenge Resource Record successfully added and validated.
/-------------------- AUTH HOOK END --------------------/
Hook '--manual-cleanup-hook' for example.com ran with output:
/------------------- CLEANUP HOOK START -------------------/
Removing challenge Resource Record...
Challenge Resource Record(s) successfully cleaned up.
/-------------------- CLEANUP HOOK END --------------------/
Hook '--manual-cleanup-hook' for example.com ran with output:
/------------------- CLEANUP HOOK START -------------------/
Removing challenge Resource Record...
Challenge Resource Record(s) successfully cleaned up.
/-------------------- CLEANUP HOOK END --------------------/
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
C:\Certbot\live\example.com\fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
While this script was written with renewals in mind, it turns out it does a nice job for creation as well. Please note however it only gets the certificates issued, you'll need to configure your software to use them manually.
Remove
--dry-run
when you're ready and it's working. DON'T try running it verbatim with the example domains!
certbot certonly --manual --preferred-challenges dns --manual-auth-hook "node.exe /certbot-epik-dns-hook/hook/auth_hook.js" --manual-cleanup-hook "node.exe /certbot-epik-dns-hook/hook/cleanup_hook.js" -d example.com -d *.example.com --dry-run
It's worth noting that if you have created all your certificates this way (including specifying the hook) you don't
actually need to re-specify the hook information at renewal time as they will be stored in the renewal config file for
certbot (C:\Certbot\renewal\example.com.conf
in my instance at least).
Once you have the script configured and know it's functioning as expected with successful cert renewals, you can include it in an automated task. As mentioned above, if you initially used Certbot with the hooks, you may not need to do this step. The scheduled task is created after using certbot
successfully on Windows is "Certbot Renew Task". By default, it runs twice a day: once at midnight and once at noon. It will only renew certs that need to be renewed each run. The existing "Start a program" action can be edited to run Powershell.exe
with these arguments:
-NoProfile -WindowStyle Hidden -Command "certbot renew --manual --manual-auth-hook 'node.exe /certbot-epik-dns-hook/hook/auth_hook.js' --manual-cleanup-hook 'node.exe /certbot-epik-dns-hook/hook/cleanup_hook.js'"
From there and as recommended for Certbot, you should point your webserver to the fullchain.pem
and privkey.pem
symlinks provided and updated by certbot
. This way your webserver uses the latest cert as automatically provided. In my case, my Apache config includes these lines:
SSLCertificateFile "/Certbot/live/example.com/fullchain.pem"
SSLCertificateKeyFile "/Certbot/live/example.com/privkey.pem"
Following these steps, you have successfully automated SSL certificate renewals for your Epik domains using the dns-01
challenge with certbot
. Enjoy!
To carry out development locally, two additional environment variables can be specified in your .env
file that would
normally be provided by running the certbot
client. Once these are set, you can just use npm start
to execute the auth script and npm run cleanup
to execute the cleanup script.
CERTBOT_DOMAIN
This specifies which domain you want to work with in Epik. It would correlate to the domain you are updating.
Example:
CERTBOT_DOMAIN=example.com
CERTBOT_VALIDATION
This is the validation string that the Letsencrypt server would specify that you have to set in your DNS for it to validate. For development it can be any string, as all we're doing is setting it in DNS and then testing it's there.
Example:
CERTBOT_VALIDATION=ARandomStringToSetAndCompare
- Anthony Nave - AN Invent
- Daniel Hopkirk - Initial work - Logical Route
This project is licensed under the MIT License.
Generally, use it and abuse it. Optional references to original authors would be appreciated.
- This is but a helper to the great service from LetsEncrypt. Much respect and thanks to them making SSL much more accessible.
- The certbot-cloudflare-dns-hook is the original script cloned and adapted for use with Epik DNS