Overview

Securing my website with HTTPS is crucial, and Certbot makes it straightforward for many domains. However, when it comes to wildcard domains (like *.domain.com), there’s a bit more work involved—particularly if I want to automate renewals.

This post explains how I set up a manual DNS hook for Certbot that integrates with my domain name provider’s API (in this example, GoDaddy), so I no longer have to manually add DNS TXT records every time I need to renew my wildcard certificate.

Why Do We Need This?

Certbot automates the HTTPS setup for many domain configurations. However, wildcard certificates require DNS-based validation—meaning I must add a TXT record to prove domain ownership. Certbot does not automatically update DNS for every provider. Thus, without automation, I’d be forced to:

  1. Run Certbot.
  2. Grab the _acme-challenge TXT record details.
  3. Log in to my DNS panel and manually create the TXT record.
  4. Wait for DNS to propagate.
  5. Resume the Certbot process.
  6. Finally, clean up the TXT record.

Doing this every few months quickly becomes tedious, especially if I manage multiple wildcard domains. Luckily, Certbot’s --manual-auth-hook parameter can help me automate these steps.

The Goal

  • Automate the DNS validation process for wildcard certificate renewals using Certbot hooks.
  • Utilize my DNS provider’s API (in my case, GoDaddy) to create and remove the required _acme-challenge TXT record automatically.
  • Integrate this process into a crontab so renewals happen on schedule without manual intervention.

Current (Manual) Process

Here’s what I was doing without automation:

  1. Run Certbot: certbot certonly --manual ...
  2. Certbot tells me which TXT record to create, e.g. "_acme-challenge.domain.com".
  3. I log into GoDaddy (or another provider) and create the TXT record with the provided value.
  4. I wait for DNS propagation (a few minutes).
  5. Certbot verifies and finalizes the certificate issuance.
  6. I remove or empty out the TXT record.

This process, while doable, is time-consuming and must be repeated every 60–90 days (depending on my renewal schedule).

Godaddy API endpoint

Automating the Workflow

To automate the renewal of my wildcard domain certificate, I leverage my domain provider’s API to manage DNS TXT records programmatically. I use GoDaddy.

Prerequisites

  1. API Access: Ensure GoDaddy supports DNS management via API.
  2. API Credentials: Obtain my API key and secret from the GoDaddy Developer Portal.

GoDaddy API Endpoint

I use the following endpoint to manage TXT records:

https://api.godaddy.com/v1/domains/${GODADDY_DOMAIN}/records/TXT/${RECORD_NAME}

Parameters:

  • ${GODADDY_DOMAIN}: My root domain (e.g., example.com).
  • ${RECORD_NAME}: Typically _acme-challenge for Certbot.

Using the API

Testing Create/Update TXT Record Endpoints

curl -s -X PUT \
  -H "Authorization: sso-key ${GODADDY_KEY}:${GODADDY_SECRET}" \
  -H "Content-Type: application/json" \
  -d "[{\"data\": \"${CERTBOT_VALIDATION}\", \"ttl\": 600}]" \
  "https://api.godaddy.com/v1/domains/${GODADDY_DOMAIN}/records/TXT/${RECORD_NAME}"
  • Headers:
    • Authorization: sso-key MY_API_KEY:MY_API_SECRET
    • Content-Type: application/json
  • Data:
    • "data": Validation string from Certbot.
    • "ttl": Time-to-live (e.g., 600 seconds).

Remove TXT Record

curl -s -X PUT \
  -H "Authorization: sso-key ${GODADDY_KEY}:${GODADDY_SECRET}" \
  -H "Content-Type: application/json" \
  -d "[]" \
  "https://api.godaddy.com/v1/domains/${GODADDY_DOMAIN}/records/TXT/${RECORD_NAME}"

Integration with Certbot Hooks

  • Auth Hook (godaddy-auth.sh): Adds the TXT record before validation.
  • Cleanup Hook (godaddy-cleanup.sh): Removes the TXT record after validation.

I ensure my scripts use the above curl commands with the appropriate environment variables (GODADDY_KEY, GODADDY_SECRET, GODADDY_DOMAIN, RECORD_NAME, CERTBOT_VALIDATION).

The Automated Solution

Certbot offers hooks that run custom scripts to automate these exact steps:

1. Command with Hooks

certbot certonly \
  --manual \
  --preferred-challenges dns \
  --manual-auth-hook /etc/letsencrypt/scripts/godaddy-auth.sh \
  --manual-cleanup-hook /etc/letsencrypt/scripts/godaddy-cleanup.sh \
  --agree-tos \
  -d '*.wild.card.domain' \
  --preferred-chain "ISRG Root X1"
  • --manual-auth-hook: Runs a script before Certbot attempts to validate the domain (to set up the TXT record).
  • --manual-cleanup-hook: Runs a script after validation completes (to remove or clear the TXT record).

2. GoDaddy Auth Script

The following script (godaddy-auth.sh) is triggered by the --manual-auth-hook. It reads environment variables set by Certbot—like CERTBOT_DOMAIN and CERTBOT_VALIDATION—and then updates the DNS record via the GoDaddy API.

#!/usr/bin/env bash
# /etc/letsencrypt/scripts/godaddy-auth.sh

# Certbot environment variables:
#  - CERTBOT_DOMAIN (the domain being authenticated)
#  - CERTBOT_VALIDATION (the validation string for TXT record)

GODADDY_KEY="domain_name_provider_key"
GODADDY_SECRET="domain_name_provider_secret"
GODADDY_DOMAIN="your_root_domain"  # e.g., "example.com"
TTL=600    

# Subdomain that needs to be updated
RECORD_NAME="_acme-challenge"  

# Build request payload
DATA="[{\"data\": \"${CERTBOT_VALIDATION}\", \"ttl\": ${TTL}}]"

curl -s -X PUT \
  -H "Authorization: sso-key ${GODADDY_KEY}:${GODADDY_SECRET}" \
  -H "Content-Type: application/json" \
  -d "${DATA}" \
  "https://api.godaddy.com/v1/domains/${GODADDY_DOMAIN}/records/TXT/${RECORD_NAME}"

echo "GoDaddy AUTH-HOOK: Created TXT record for ${CERTBOT_DOMAIN}."

# Sleep to allow DNS propagation
sleep 60

Note: If I have a subdomain or different domain structure, I adjust RECORD_NAME accordingly.

3. GoDaddy Cleanup Script

This script (godaddy-cleanup.sh) runs after verification succeeds. It removes (or resets) the _acme-challenge TXT record, keeping my DNS tidy.

#!/usr/bin/env bash
# /etc/letsencrypt/scripts/godaddy-cleanup.sh

# Certbot environment variables:
#  - CERTBOT_DOMAIN (the domain being authenticated)

GODADDY_KEY="domain_name_provider_key"
GODADDY_SECRET="domain_name_provider_secret"
GODADDY_DOMAIN="your_root_domain"

RECORD_NAME="_acme-challenge"

# Empty the TXT record (or remove it altogether)
DATA="[]"

curl -s -X PUT \
  -H "Authorization: sso-key ${GODADDY_KEY}:${GODADDY_SECRET}" \
  -H "Content-Type: application/json" \
  -d "${DATA}" \
  "https://api.godaddy.com/v1/domains/${GODADDY_DOMAIN}/records/TXT/${RECORD_NAME}"

echo "GoDaddy CLEANUP-HOOK: Removed TXT record for ${CERTBOT_DOMAIN}."

Scheduling With Crontab

After confirming the manual hooks work, I automate the renewal checks using crontab:

10 0 * * * /usr/bin/certbot renew --preferred-chain "ISRG Root X1" >> /folder/to/save/cronlog.log 2>&1

10 0 * * * /etc/letsencrypt/scripts/certbot-renew-dns.sh >> /folder/to/save/cronlog-manualhook.log 2>&1

Pro Tips

  • DNS Propagation: Sometimes DNS changes can take longer than expected, especially if my DNS TTL is high. I might adjust my sleep time or TTL in the script if validations fail.
  • Permissions: I ensure my hook scripts are executable by using chmod +x /path/to/script.sh.
  • Security: I keep my API keys secret. Storing them in environment variables or a secure file is best.
  • Testing: I run certbot renew --dry-run to verify that my hooks and scripts work before scheduling them in production.

Conclusion

Using Certbot’s DNS challenge manual hook scripts, I can seamlessly automate the issuance and renewal of wildcard certificates. Gone are the days of logging into my DNS provider’s dashboard every few months. With minimal scripting and a few Cron entries, my wildcard certificates can renew without me lifting a finger.

Leave a comment below to share your experience or ask questions!

Merry Christmas & A Happy New Year, See ya soon~