Certbot and DNS with BIND and Windows

wiki.TerraBase.info
Revision as of 22:22, 1 August 2025 by Root (talk | contribs)
Jump to navigation Jump to search

What a blessed hassle it is. Here's what needs to be done.

Script to Run (work in progress)

The below script, when run with ./NC.sh, will use DNS to retrieve certificates (and also update other 'Slave Servers'). That infrastructure has to be set up before hand, and includes the following;

  • _acme_challenge 'sub zone'
  • "RNDC Setup"
  • If using external / internal DNS Servers, then that configuration too.
#!/bin/sh

DomainName="$1"

TotalSlaveServers=1

SlaveServer1=W1.X1.Y1.Z1
SlaveServerKey1=WhatEverKey1

SlaveServer2=W2.X2.Y2.Z2
SlaveServerKey2=WhatEverKey2


if [ -z "${DomainName}" ]; then
	echo
	echo "Don't forget to add the Domain Name to the end of the command."
	echo "Example: ./NewCertificate.via.DNS.sh terrawide.com"
	echo
	exit 1
else
	echo
	echo "Command Line contains Domain Name: ${DomainName}"
	echo
fi



i=1

while [ "$i" -le "$TotalSlaveServers" ]; do

	eval SlaveIP="\$SlaveServer${i}"

	# Create fresh RNDC temp file for this slave
	rm -f /etc/letsencrypt/SCRIPTS/RNDC.TempFile
	(
		echo 'key "rndc-key" {'
		echo '	algorithm hmac-sha256;'
		echo "	secret \"${SlaveServerKey1}\";"
		echo '};'
		echo
		echo 'options {'
		echo "	default-key \"rndc-key\";"
		echo "	default-server ${SlaveIP};"
		echo '	default-port 953;'
		echo '};'
	) > /etc/letsencrypt/SCRIPTS/RNDC.TempFile

	# Test the zone on this slave
	if /usr/sbin/rndc -c /etc/letsencrypt/SCRIPTS/RNDC.TempFile zonestatus "_acme-challenge.${DomainName}" > /dev/null 2>&1; then
		echo
		echo "_acme-challenge.${DomainName} Zone Exists on ${SlaveIP}"
		echo
	else
		echo
		echo "_acme-challenge.${DomainName} Zone Does NOT exist on ${SlaveIP}"
		echo
		rm -f /etc/letsencrypt/SCRIPTS/RNDC.TempFile
		exit 1
	fi

	rm -f /etc/letsencrypt/SCRIPTS/RNDC.TempFile
	i=$((i + 1))
done



### Remove --staging for a 'Real / Live Certificate';

certbot certonly \
	--manual \
	--preferred-challenges dns \
	--manual-auth-hook /etc/letsencrypt/renewal-hooks/pre/ManualAuth.sh \
	--manual-cleanup-hook /etc/letsencrypt/renewal-hooks/post/ManualCleanUp.sh \
	--non-interactive \
	--cert-name "${DomainName}" \
	-d "${DomainName}"

certbot certonly \
	--manual \
	--preferred-challenges dns \
	--manual-auth-hook /etc/letsencrypt/renewal-hooks/pre/ManualAuth.sh \
	--manual-cleanup-hook /etc/letsencrypt/renewal-hooks/post/ManualCleanUp.sh \
	--non-interactive \
	--cert-name "${DomainName}-WILDCARD" \
	-d "*.${DomainName}"


### Staging versions of above (REMEMBER: Don't comment individual items out out, it won't work below cuz those \ ( backslashes ) indicate 'one continuous line', not separate lines. )
### certbot certonly \
### 	--manual \
### 	--preferred-challenges dns \
### 	--manual-auth-hook /etc/letsencrypt/renewal-hooks/pre/ManualAuth.sh \
### 	--manual-cleanup-hook /etc/letsencrypt/renewal-hooks/post/ManualCleanUp.sh \
### 	--staging \
### 	--non-interactive \
### 	--cert-name "${DomainName}" \
### 	-d "${DomainName}"

### certbot certonly \
### 	--manual \
### 	--preferred-challenges dns \
### 	--manual-auth-hook /etc/letsencrypt/renewal-hooks/pre/ManualAuth.sh \
### 	--manual-cleanup-hook /etc/letsencrypt/renewal-hooks/post/ManualCleanUp.sh \
### 	--staging \
### 	--non-interactive \
### 	--cert-name "${DomainName}-WILDCARD" \
### 	-d "*.${DomainName}"

Big ASH Gotcha!

If you use the preconfigured Directory Structure Let's Encrypt / Certbot provides in /etc/letsencrypt/renewal-hooks, watch out!

When renewing a Certificate it automatically runs everything it finds in the above mentioned Directory, like for instance: /etc/letsencrypt/renewal-hooks/pre/WhatEver.sh

In the instance of the /etc/letsencrypt/renewal/WhatEverRenewalFile below (WHICH CERTBOT AUTOMATICALLY CREATES ITSELF WHEN GETTING A NEW CERTIFICATE!!!);

# renew_before_expiry = 30 days
version = 2.9.0
archive_dir = /etc/letsencrypt/archive/WhatEverDomain.com
cert = /etc/letsencrypt/live/WhatEverDomain.com/cert.pem
privkey = /etc/letsencrypt/live/WhatEverDomain.com/privkey.pem
chain = /etc/letsencrypt/live/WhatEverDomain.com/chain.pem
fullchain = /etc/letsencrypt/live/WhatEverDomain.com/fullchain.pem

# Options used in the renewal process
[renewalparams]
account = WhatEverAccountNumber
pref_challs = dns-01,
authenticator = manual
manual_auth_hook = /etc/letsencrypt/renewal-hooks/pre/ManualAuth.sh
manual_cleanup_hook = /etc/letsencrypt/renewal-hooks/post/ManualCleanUp.sh
server = https://acme-v02.api.letsencrypt.org/directory
key_type = ecdsa

Guess how many times the WhatEver.sh Script in the /etc/letsencrypt/renewal-hooks/pre/ runs? Once, as one might think from the above Renewal Config File? Nope, TWICE!

Yup, that's right. Everything in the /etc/letsencrypt/renewal-hooks/pre/ will be run. Then anything listed in the Renewal Config File will be run. Woof!

LESSON LEARNED: Put hooks in a CUSTOM Directory Structure, NOT in the one provided by Let's Encrypt!