Skip to content

fix: migrate POST/PATCH to v2 API to fix DNS-01 ACME challenge - #6

Open
WEBzaytsev wants to merge 1 commit into
libdns:mainfrom
WEBzaytsev:main
Open

fix: migrate POST/PATCH to v2 API to fix DNS-01 ACME challenge#6
WEBzaytsev wants to merge 1 commit into
libdns:mainfrom
WEBzaytsev:main

Conversation

@WEBzaytsev

Copy link
Copy Markdown

Problem

DNS-01 ACME challenges fail with HTTP 400: bad_subdomain_name when using
acme_dns timeweb in Caddy. The provider is unable to create TXT records
for _acme-challenge.* subdomains.

Root Cause

The v1 POST endpoint (/api/v1/domains/{zone}/dns-records) rejects names
starting with _ in the subdomain request body field. The provider was
sending the relative name (e.g. _acme-challenge.sub) instead of the full
FQDN (_acme-challenge.sub.example.com) that v1 requires.

Additionally, the v1 POST and PATCH endpoints are marked as deprecated in
the Timeweb OpenAPI spec.

Solution

Migrate createRecord and updateRecord to the v2 API, where the target
FQDN is specified in the URL path (already used by deleteRecord) and the
request body contains no subdomain field:

POST /api/v2/domains/_acme-challenge.sub.example.com/dns-records {"type":"TXT","value":"...","ttl":600}

Changes

  • client.go: createRecord and updateRecord now use v2 + getFQDN()
    in the URL path, consistent with the existing deleteRecord
  • models.go: replaced TimewebRecord / SavedRecord (v1) with
    TimewebRecordV2 / RecordResponseV2 / SavedRecordV2 (v2); simplified
    libdnsToRecord — no subdomain field, no zone parameter needed
  • GET (user-records) stays on v1 — no v2 equivalent exists in the spec

References

Timeweb OpenAPI spec: POST /api/v2/domains/{fqdn}/dns-records
RFC 8555 §8.4 (DNS-01 challenge)

@veynko

veynko commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Hey, thanks for taking the time to investigate this and put together such a detailed PR — really appreciate it!

I've just re-tested the library end-to-end with Caddy using the caddy-dns/timeweb plugin against Let's Encrypt staging, and DNS-01 challenges are passing successfully — _acme-challenge TXT records go through the v1 API without any issues.

The reason I deliberately stayed on v1 for POST/PATCH is that v2 requires subdomain pre-creation before you can attach records to it — as you can see from your own implementation, it adds a fair amount of extra logic. The v1 API doesn't have that requirement, which keeps things simpler. On top of that, v1 doesn't reject _-prefixed names in the subdomain field — the challenge records go through fine.

That said, if bad_subdomain_name errors are happening for you specifically, it might be a configuration issue on the Caddy/plugin side rather than in the library itself. I'd be happy to help you debug it — could you share your Caddy config (with secrets redacted) and the exact request/response that's failing? That would help narrow down where things are going wrong.

@veynko veynko self-assigned this Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants