[Solved] Certificate creation failed using Certbot, dns challenge and Gandi DNS servers

Hi,

I tried to create a certificate for both domains dinot.net and www.dinot.net, using:

  • Certbot
  • DNS challenge
  • Lexicon
  • A domain provided by Gandi (I am using Gandi DNS and API)

I followed this recipe:

https://id-rsa.pub/post/certbot-auto-dns-validation-with-lexicon/

My domain is:

dinot.net

I ran this command:

/usr/bin/certbot certonly \
    --manual \
    --manual-public-ip-logging-ok \
    --manual-auth-hook "/etc/letsencrypt/lexicon-gandi.sh create" \
    --manual-cleanup-hook "/etc/letsencrypt/lexicon-gandi.sh delete" \
    --preferred-challenges dns \
    -d dinot.net \
    -d www.dinot.net

/etc/letsencrypt/lexicon-gandi.sh content:

#!/bin/bash
/usr/local/bin/lexicon gandi \
    --auth-token="xxxxxxxxxxxxxxxxxxxxxxxx" \
    "$1" "${CERTBOT_DOMAIN}" TXT \
    --name "_acme-challenge.${CERTBOT_DOMAIN}" \
    --content "${CERTBOT_VALIDATION}" || exit 255

if [ "$1" == "create" ]; then
  sleep 30
fi

NB: in the copy above, I replaced my real API key by “xxxxxxxxxxxxxxxxxxxxxxxx”

It produced this output:

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for dinot.net
dns-01 challenge for www.dinot.net
Output from lexicon-gandi.sh:
Arguments: Namespace(action='create', auth_token='xxxxxxxxxxxxxxxxxxxxxxxx', content='yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy', delegated=None, domain='dinot.net', identifier=None, log_level='DEBUG', name='_acme-challenge.dinot.net', priority=None, provider_name='gandi', ttl=None, type='TXT')
create_record: True

Output from lexicon-gandi.sh:
Arguments: Namespace(action='create', auth_token='xxxxxxxxxxxxxxxxxxxxxxxx', content='zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz', delegated=None, domain='www.dinot.net', identifier=None, log_level='DEBUG', name='_acme-challenge.www.dinot.net', priority=None, provider_name='gandi', ttl=None, type='TXT')
create_record: True

Waiting for verification...
Cleaning up challenges
Output from lexicon-gandi.sh:
Arguments: Namespace(action='delete', auth_token='xxxxxxxxxxxxxxxxxxxxxxxx', content='yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy', delegated=None, domain='dinot.net', identifier=None, log_level='DEBUG', name='_acme-challenge.dinot.net', priority=None, provider_name='gandi', ttl=None, type='TXT')
delete_record: True

Output from lexicon-gandi.sh:
Arguments: Namespace(action='delete', auth_token='xxxxxxxxxxxxxxxxxxxxxxxx', content='zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz', delegated=None, domain='www.dinot.net', identifier=None, log_level='DEBUG', name='_acme-challenge.www.dinot.net', priority=None, provider_name='gandi', ttl=None, type='TXT')
delete_record: True

Failed authorization procedure. www.dinot.net (dns-01): urn:acme:error:connection :: The server could not connect to the client to verify the domain :: DNS problem: NXDOMAIN looking up TXT for _acme-challenge.www.dinot.net, dinot.net (dns-01): urn:acme:error:connection :: The server could not connect to the client to verify the domain :: DNS problem: NXDOMAIN looking up TXT for _acme-challenge.dinot.net

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: www.dinot.net
   Type:   connection
   Detail: DNS problem: NXDOMAIN looking up TXT for
   _acme-challenge.www.dinot.net

   Domain: dinot.net
   Type:   connection
   Detail: DNS problem: NXDOMAIN looking up TXT for
   _acme-challenge.dinot.net

   To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A/AAAA record(s) for that domain
   contain(s) the right IP address. Additionally, please check that
   your computer has a publicly routable IP address and that no
   firewalls are preventing the server from communicating with the
   client. If you're using the webroot plugin, you should also verify
   that you are serving files from the webroot path you provided.

My web server is (include version):

Apache HTTPd 2.4.29

The operating system my web server runs on is (include version):

Debian buster

My hosting provider, if applicable, is:

Myself

I can login to a root shell on my machine (yes or no, or I don’t know):

Yes

I’m using a control panel to manage my site (no, or provide the name and version of the control panel):

No

Additional information:

  • After several unsuccessful tries, I stopped my web server and my firewall but it didn’t bring any change.

  • The DNS zone was temporarily updated like here below:

      _acme-challenge     3600 IN TXT "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
      _acme-challenge.www 3600 IN TXT "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
    

Could you help me please? I don’t understand why this process fails after the deletion of the records.

You can modify the sleep 30 to a longer value for debugging purposes, for example, to 300 (5 minutes).

While the creation script is waiting (it should have added the TXT records at that moment), you might want to verify if the TXT records are actually visible to the outside world.

It could be you can see them in your zone file, but it isn’t actually transfered to the resolving DNS servers.

You might test it with a command (while the script is in its “sleep” period of course!) like: dig +trace _acme-challenge.www.dinot.net TXT

Or use the site https://unboundtest.com/ which tries to resemble the resolver used by Let’s Encrypts ACME server as good as possible, but it has a lot of verbose output, so it might not say much to a novice user.

1 Like

According to one page on your DNS provider's website:

While our classic DNS service pushed zone file changes once every 20 minutes, the LiveDNS service does so immediately after each change.

https://doc.gandi.net/en/dns

I believe you're using Gandi's "classic" DNS platform. You could try upgrading to LiveDNS, but it might not be a production service yet, and you may need a new API client.

1 Like

An alternative is changing sleep 30 to sleep 1200.

2 Likes

Indeed, Lexicon is working to support LiveDNS in the existing Gandi integration but it isn't merged yet, so you would need to wait or find another client if you wanted to use it.

As the author of the post I agree with @Osiris that using sleep 1200 would be the way to go. It means that you would need to wait 20 minutes for the command to succeed, but you only need to worry about that once. In future the automated renewals would also take 20 minutes, but since this happens automatically in the background, it shouldn't matter to you.

1 Like

A big thanks to @Osiris and @mnordhoff. Increasing the delay to 1200 seconds was the solution.

With reference to Gandi LiveDNS, as far as I know, the new API (v5) required to use this service, is not available yet.

Actually, sometimes, waiting 1200 seconds is not enough. I increased the value to 1500 seconds.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.