Skip to content

DNS Challenge example

serverco edited this page Apr 14, 2016 · 4 revisions

As an example of using the DNS challenge, in the getssl config file for the domain I have

# The staging server is best for testing
CA="https://acme-staging.api.letsencrypt.org"
# This server issues full certificates, however has rate limits
#CA="https://acme-v01.api.letsencrypt.org"

# additional domains - this could be multiple domains / subdomains in a comma separated list
SANS=www.example.com

#Use the following 3 variables if you want to validate via DNS
VALIDATE_VIA_DNS="true"
DNS_ADD_COMMAND="/home/me/scripts/dns_add_acme_challenge"
DNS_DEL_COMMAND="/home/me/scripts/dns_del_acme_challenge"

An example script for "dns_add_acme_challenge" using cloudflare (you can use cloudflare as free DNS, and it has a good API) is;

#!/bin/bash

fulldomain="$1"
token="$2"
email="[email protected]"
key="key"

NumParts=$(echo "$fulldomain" | awk -F"." '{print NF}')
if [[ $NumParts -gt 2 ]]; then
  domain=$(echo "$fulldomain" | awk -F\. '{print $(NF-1) FS $NF}')
  txtname="_acme-challenge$(echo $fulldomain | awk -F\. '{for (i=1; i<NF-1; i++) printf "." $i}')"
else
  domain=$fulldomain
  txtname="_acme-challenge"
fi

response=$(curl --silent -X GET "https://api.cloudflare.com/client/v4/zones?name=${domain}&match=all" \
  -H "X-Auth-Email: ${email}" -H "X-Auth-Key: ${key}" -H "Content-Type: application/json")

domain_id=$(echo "$response" | egrep -o  "{[^{]*\"name\":\"${domain}\"[^}]*"|grep -oP '\"id\":"\K[^"]+')

response=$(curl --silent -X POST "https://api.cloudflare.com/client/v4/zones/${domain_id}/dns_records" \
  -H "X-Auth-Email: ${email}" -H "X-Auth-Key: ${key}" -H "Content-Type: application/json" \
  --data "{\"type\":\"TXT\",\"name\":\"${txtname}\",\"content\":\"$token\",\"ttl\":300}")

and an example script for clearing up the dns challenge afterwards on cloudflare - dns_del_acme_challenge - is;

#!/bin/bash

fulldomain="$1"
email="[email protected]"
key="key"

NumParts=$(echo "$fulldomain" | awk -F"." '{print NF}')
if [[ $NumParts -gt 2 ]]; then
  domain=$(echo "$fulldomain" | awk -F\. '{print $(NF-1) FS $NF}')
  txtname="_acme-challenge$(echo $fulldomain | awk -F\. '{for (i=1; i<NF-1; i++) printf "." $i}')"
else
  domain=$fulldomain
  txtname="_acme-challenge"
fi

response=$(curl --silent -X GET "https://api.cloudflare.com/client/v4/zones?name=${domain}&match=all" \
-H "X-Auth-Email: ${email}" -H "X-Auth-Key: ${key}" -H "Content-Type: application/json")

domain_id=$(echo "$response" | egrep -o  "{[^{]*\"name\":\"${domain}\"[^}]*"|grep -oP '\"id\":"\K[^"]+')

response=$(curl --silent -X GET "https://api.cloudflare.com/client/v4/zones/${domain_id}/dns_records?type=TXT&name=${txtname}.${domain}" \
-H "X-Auth-Email: ${email}" -H "X-Auth-Key: ${key}" -H "Content-Type: application/json")

zone_ids=$(echo "$response" |grep -oP '\"id\":"\K[^"]+')

ids=( $zone_ids )

# loop though all ( if more than one )
for id in "${ids[@]}"; do
  response=$(curl --silent -X DELETE "https://api.cloudflare.com/client/v4/zones/${domain_id}/dns_records/${id}" \
  -H "X-Auth-Email: ${email}" -H "X-Auth-Key: ${key}" -H "Content-Type: application/json")
done

There is a script ( written in python - lexicon ) which provides a generic way to add DNS records to DNS providers who have API's. There are 10 providers supported right now, and more planned.