You are here
Matthew - Tue, 2025/06/17 - 04:59
Hi there. I've been having issues with Let's Encrypt via the dns-01 method in confconsole and am looking for help.
Forum:
Hi there. I've been having issues with Let's Encrypt via the dns-01 method in confconsole and am looking for help.
Hi Matthew, could you please provide some more info
Hi Matthew, could you please provide some more info.
Are you getting specific errors? Or is it just not working? Or something else?
Lexicon, Cloudflare, and dns-01
Thanks for replying. Here's what I've found out so far. For whatever reason, I think the auth_token isn't working with lexicon/confconsole, resulting in the following error (actual domain name removed):
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.cloudflare.com/client/v4/zones?name=example.com
Running the below command from the terminal produces the same error:
# lexicon --config-dir /etc/dehydrated/ auto list example.com A
I've tried both account owned and user owned API tokens, as well as the global API key, without success. The tokens I created aren't restricted to any particular zone, but I tried both with and without the zone_id in the lexicon_auto.yml file and neither worked.
The following works from the terminal, however, with either a valid user or account API key (actual key & domain removed):
# curl "https://api.cloudflare.com/client/v4/zones?name=example.com" -H "Authorization: Bearer 1234567890123456789012345678901234567890"
Any help would be appreciated.
Thanks,
Matt
Also...
Also, the following (with the correct info) works with the account API token:
LEXICON_CLOUDFLARE_TOKEN="1234567890123456789012345678901234567890" lexicon --config-dir /etc/dehydrated/ auto list example.com A
Maybe the config file is not used correctly?
I sort of figured it out.
I sort of figured it out. I ignored lexicon_auto.yml and manually created a lexicon.yml in /etc/dehydrated/ as follows:
cloudflare:
auth_token: 1234567890123456789012345678901234567890 # Account API Token
So I guess I'm writing the lexicon_auto.yml config file incorrectly, but https://dns-lexicon.github.io/dns-lexicon/configuration_reference.html doesn't say very much about "the auto provider." I tried a few different ways and couldn't get it working. It would be nice if I could do it the "right" way so it showed up in confconsole if you have any insight.
Thanks for the additional info
Thanks for the additional info and even better that you worked out a resolution.
TBH it's been a long time since I worked on that code but I've just had a quick look over it to refresh my memory. FYI the way it's meant to work is that if you select cloudflare as the provider, it should copy the example lexicon cloudflare config to /etc/dehydrated/lexicon_cloudflare.yml. Here's the example config:
Given what you've noted, updating "example 2" should have done the trick. I.e. removing the leading '#' and replacing 'YOUR_CF_UNSCOPED_API_TOKEN'. E.g. using your example the relevant section of the updated file should look like this:
During that process, Confconsole should also explicitly set the provider as "cloudflare" and when 'turnkey-lexicon' runs (the lexicon wrapper that we provide) it should automatically use that that /etc/dehydrated/lexicon_cloudflare.yml file and include "cloudflare" as the provider when it calls lexicon. Currently only cloudflare and aws-route53 have example config - otherwise it will just provide an "auto" example config file - and try to use the "auto" process.
Obviously that either didn't work as expected and we have a bug - or there was some misunderstanding along the way. Either way we need to improve that as your experience is not how it should be.
Rereading your posts, it sounds like you ended up with an "auto" config yaml file in /etc/dehydrated, rather than the cloudflare specific one? So if I understand correctly, you ended up writing your own lexicon.yml file and then it worked ok?
FWIW when we added DNS-01 support, I only explicitly tested AWS Route53 myself. But another user tested the Cloudflare pathway and he said that it worked ok. So I'm not really sure what has happened there?!
Armed with a little more info of exactly what you saw/experienced I can dig in a bit deeper and improve things so it works as expected.
Thanks again for taking the time to report this.
It's not you, it's me...
Thanks for the additional info
Thanks for the info, that makes sense.
AFAIK the "auto" config just uses the specific DNS provider config and tries to guess your provider, hence why the "auto" docs are limited. Although your note about failure trying to use an alternate DNS provider suggests not...
Regardless, in an effort to make things more obvious/explicit I've added more info in the templates. Do you think that might have made things clearer and easier for you?
Any additional suggestions/modifications warmly welcomed.
Thank you
Yeah, I can't get the cloudflare Option to work at all.
My host is a VM on a Proxmox Cluster that has unabated access to the Internet, but nothing exposed on the Internet (and no way to open port 80), so I was working through the DNS option as well, but I can't make it work.
It did create the lexicon_cloudflare.yml file. I tried all 3 methods and all failed with the same HTTPError 400 Client Error: Bad Request.
I did move that to a backup file and created a simple lexixon.yaml file as the OP did, it looked like it worked, once, but I never got a certificate :/ (it didn't error though). I manually ran it again from the terminal and basically am stuck at the same spot.
/usr/lib/confconsole/plugins.d/Lets_Encrypt/dehydrated-wrapper --force
[2025-07-15 17:37:21] dehydrated-wrapper: INFO: started
[2025-07-15 17:37:21] dehydrated-wrapper: INFO: found apache2 listening on port 443
[2025-07-15 17:37:21] dehydrated-wrapper: INFO: running dehydrated
Traceback (most recent call last):
File "/usr/local/src/venv/lexicon/bin/lexicon", line 8, in <module>
sys.exit(main())
^^^^^^
File "/usr/local/src/venv/lexicon/lib/python3.11/site-packages/lexicon/_private/cli.py", line 135, in main
results = client.execute()
^^^^^^^^^^^^^^^^
File "/usr/local/src/venv/lexicon/lib/python3.11/site-packages/lexicon/client.py", line 212, in execute
executor = self.__enter__()
^^^^^^^^^^^^^^^^
File "/usr/local/src/venv/lexicon/lib/python3.11/site-packages/lexicon/client.py", line 169, in __enter__
raise e
File "/usr/local/src/venv/lexicon/lib/python3.11/site-packages/lexicon/client.py", line 162, in __enter__
provider.authenticate()
File "/usr/local/src/venv/lexicon/lib/python3.11/site-packages/lexicon/_private/providers/auto.py", line 242, in authenticate
proxy_provider.authenticate()
File "/usr/local/src/venv/lexicon/lib/python3.11/site-packages/lexicon/_private/providers/cloudflare.py", line 56, in authenticate
payload = self._get("/zones", {"name": self.domain})
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/src/venv/lexicon/lib/python3.11/site-packages/lexicon/interfaces.py", line 163, in _get
return self._request("GET", url, query_params=query_params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/src/venv/lexicon/lib/python3.11/site-packages/lexicon/_private/providers/cloudflare.py", line 218, in _request
response.raise_for_status()
File "/usr/local/src/venv/lexicon/lib/python3.11/site-packages/requests/models.py", line 1026, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.cloudflare.com/client/v4/zones?name=mydomain.com
ERROR: deploy_challenge hook returned with non-zero exit code
[2025-07-15 17:37:24] dehydrated-wrapper: FATAL: dehydrated exited with a non-zero exit code.
[2025-07-15 17:37:24] dehydrated-wrapper: INFO: Cleaning backup cert & key
[2025-07-15 17:37:24] dehydrated-wrapper: INFO: (Re)starting apache2
[2025-07-15 17:37:24] dehydrated-wrapper: INFO: (Re)starting webmin.service
[2025-07-15 17:37:26] dehydrated-wrapper: INFO: dehydrated-wrapper completed successfully.
Any help appreciated.
It looks like Cloudflare are blocking your access
It looks like Cloudflare are blocking your login. A 400 error when connecting to Cloudflare suggests that there is something wrong with your authentication config.
The first 2 things to double check:
The updated config discussed in this thread won't be included in the version of Confconsole you have installed - but the important bits remain the same.
As an example of the config contents using an unscoped API key with a value of 'ABCDEFGHIJKLMNOP'. The updated lexicon Cloudflare config provided by Confconsole should look like this:
Note that all irrelevant lines are commented (i.e. a preceeding '#'), leaving only the 'auth_token' line - the only key/value that should be used with an unscoped API key.
If you've double checked both of those things and are sure that you have it right, please share the output of the following:
Also please provide the contents of any/all lexicon yaml ('.yml') config files. Before posting the output, be sure to redact any authentication secrets (username, API key, etc). Replace the secret/s with "REDACTED" or similar so we can see the full config, but not any of the values.
Also here are the relevant Cloudflare API permissions
Also here are the relevant Cloudflare API permissions.
If using an unscoped API token:
Or if using a scoped API token:
As is likely obvious a global API key already has permission to do anything and everything (hence why it's not an ideal option).
Here's the deets you've requested.
Like the original poster, all of the curl URL tests pass from the host with all of the credentials I've tried, and I've tried all (3). Unlike the original poster, I did choose Cloudflare in the beginning, so the creds are being populated in lexicon_cloudflare.yml.
Who's contents are currently:
root@wiki /etc/dehydrated# cat lexicon_cloudflare.yml
# uncomment relevant lines and replace example value(s)
# Cloudflare example 1 - using global api key
#auth_username: <account@email>
#auth_token: 220490<redacted>6352bb72
# Cloudflare example 2 - using unscoped API token
auth_token: 2rTJr<redacted>xsvXAEH
# Cloudflare example 3 - using scoped API token
#auth_token: GF3whc<redacted>sgzs1
#zone_id: 980efd<redacted>739960
Unscoped key test:
root@wiki /etc/dehydrated# curl "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer 2rTJr<redacted>svXAEH"
{"result":{"id":"0990e7d6f7e1dc9933883b93a442e99a","status":"active","not_before":"2025-07-15T00:00:00Z","expires_on":"2025-07-26T23:59:59Z"},"success":true,"errors":[],"messages":[{"code":10000,"message":"This API Token is valid and active","type":null}]}root@wiki /etc/dehydrated#
Scoped key test:
root@wiki /etc/dehydrated# curl "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer GF3whc<redacted>sgzs1"
{"result":{"id":"6e220fc2ece3d018c3478f9a6415ed6a","status":"active","not_before":"2025-07-15T00:00:00Z","expires_on":"2025-07-26T23:59:59Z"},"success":true,"errors":[],"messages":[{"code":10000,"message":"This API Token is valid and active","type":null}]}root@wiki /etc/dehydrated#
But the error remains the same, executed through confconsole or manually via:
/usr/lib/confconsole/plugins.d/Lets_Encrypt/dehydrated-wrapper --force
I'm open to spinning up a zoom if someone wants to have a look :) Just let me know.
FIXED
OK,
After poking around, it appeared that the login request was malformed. I was able to verify that my token work (curling the URL and listing my zones and what not).
Turns out, if I entered more than one domain, or more than one host, is was breaking it. Even though I could see that it called out n number of hosts. If I just went with a single domain it worked. I could not generate a host specific cert, but was able to create a wildcard cert. So I'm currently good to go.
Hi Matt, glad to hear you worked it out.
Deep apologies that I missed your posts earlier (not sure how/why?!). Anyway, I'm glad that you've got a solution, although that does sound like a bug of some sort somewhere.
When I get a chance I'll test it myself and see if I can work it out. FWIW I have tested multiple (sub)domains via HTTP-01 and tested a single domain via DNS-01, as well as wildcard domain. But I don't think I've tested multiple domains via DNS-01 myself.
Regardless, thanks for reporting and I'm really glad you can move forward now.
Add new comment