DNS challenge with cloudflare

1. The problem I’m having:

I’m trying to obtain a TLS certificate using Caddy with the DNS challenge and Cloudflare as my DNS provider. However, the DNS challenge fails and Caddy is unable to present the required DNS record. Despite verifying that the container has full internet access and testing the Cloudflare API (which responds correctly), the challenge fails with a lot of errors.

I tried to use chatgpt gemini but i found no solution.

2. Error messages and/or full log output:

84","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["472"],"Content-Type":["application/json"],"Date":["Fri, 04 Apr 2025 13:11:50 GMT"],"Link":["<https://acme-staging-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["2tykYePSczpDu9fexDiVN3t0H_5KnxwazSZQk-elcp3pdeGhRxA"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
{"level":"debug","ts":1743772311.1647732,"msg":"http request","method":"POST","url":"https://acme-staging-v02.api.letsencrypt.org/acme/cert/2cd7927212daec563a470cc6d2c94004858f","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["3067"],"Content-Type":["application/pem-certificate-chain"],"Date":["Fri, 04 Apr 2025 13:11:51 GMT"],"Link":["<https://acme-staging-v02.api.letsencrypt.org/directory>;rel=\"index\"","<https://acme-staging-v02.api.letsencrypt.org/acme/cert/2cd7927212daec563a470cc6d2c94004858f/1>;rel=\"alternate\""],"Replay-Nonce":["2tykYePSXlmKEMVULODWdz-jeN6ZIhlK1fdbT2MNm08DrEKbRww"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
{"level":"debug","ts":1743772311.1649537,"msg":"getting renewal info","names":["test.home-lab.li"]}
{"level":"debug","ts":1743772311.4218931,"msg":"http request","method":"GET","url":"https://acme-staging-v02.api.letsencrypt.org/draft-ietf-acme-ari-03/renewalInfo/oXQaBm1Qt4YtSizBfrSNiElszRY.LNeSchLa7FY6RwzG0slABIWP","headers":{"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["101"],"Content-Type":["application/json"],"Date":["Fri, 04 Apr 2025 13:11:51 GMT"],"Link":["<https://acme-staging-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Retry-After":["21600"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
{"level":"info","ts":1743772311.4219947,"msg":"got renewal info","names":["test.home-lab.li"],"window_start":1748876241,"window_end":1749031691,"selected_time":1748921673,"recheck_after":1743793911.421988,"explanation_url":""}
{"level":"debug","ts":1743772311.671596,"msg":"http request","method":"POST","url":"https://acme-staging-v02.api.letsencrypt.org/acme/cert/2cd7927212daec563a470cc6d2c94004858f/1","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["2510"],"Content-Type":["application/pem-certificate-chain"],"Date":["Fri, 04 Apr 2025 13:11:51 GMT"],"Link":["<https://acme-staging-v02.api.letsencrypt.org/directory>;rel=\"index\"","<https://acme-staging-v02.api.letsencrypt.org/acme/cert/2cd7927212daec563a470cc6d2c94004858f/0>;rel=\"alternate\""],"Replay-Nonce":["cFzjDXVwQKKwpKedQo3m1-0yQKf1aplynPjDUJ3tIIRUz80KmO8"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
{"level":"debug","ts":1743772311.6717796,"msg":"getting renewal info","names":["test.home-lab.li"]}
{"level":"debug","ts":1743772311.9237158,"msg":"http request","method":"GET","url":"https://acme-staging-v02.api.letsencrypt.org/draft-ietf-acme-ari-03/renewalInfo/oXQaBm1Qt4YtSizBfrSNiElszRY.LNeSchLa7FY6RwzG0slABIWP","headers":{"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["101"],"Content-Type":["application/json"],"Date":["Fri, 04 Apr 2025 13:11:51 GMT"],"Link":["<https://acme-staging-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Retry-After":["21600"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
{"level":"info","ts":1743772311.9238791,"msg":"got renewal info","names":["test.home-lab.li"],"window_start":1748876241,"window_end":1749031691,"selected_time":1749030688,"recheck_after":1743793911.9238513,"explanation_url":""}
{"level":"info","ts":1743772311.9239392,"msg":"successfully downloaded available certificate chains","count":2,"first_url":"https://acme-staging-v02.api.letsencrypt.org/acme/cert/2cd7927212daec563a470cc6d2c94004858f"}
{"level":"debug","ts":1743772311.9239726,"logger":"tls.issuance.acme","msg":"selected certificate chain","url":"https://acme-staging-v02.api.letsencrypt.org/acme/cert/2cd7927212daec563a470cc6d2c94004858f"}
{"level":"debug","ts":1743772311.9243572,"logger":"tls.issuance.acme","msg":"using existing ACME account because key found in storage associated with email","email":"","ca":"https://acme-v02.api.letsencrypt.org/directory"}
{"level":"info","ts":1743772311.9243886,"logger":"tls.issuance.acme","msg":"waiting on internal rate limiter","identifiers":["test.home-lab.li"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
{"level":"info","ts":1743772311.9244044,"logger":"tls.issuance.acme","msg":"done waiting on internal rate limiter","identifiers":["test.home-lab.li"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
{"level":"info","ts":1743772311.924417,"logger":"tls.issuance.acme","msg":"using ACME account","account_id":"https://acme-v02.api.letsencrypt.org/acme/acct/2320609367","account_contact":[]}
{"level":"debug","ts":1743772311.9244545,"msg":"creating order","account":"https://acme-v02.api.letsencrypt.org/acme/acct/2320609367","identifiers":["test.home-lab.li"]}
{"level":"debug","ts":1743772312.7700331,"msg":"http request","method":"HEAD","url":"https://acme-v02.api.letsencrypt.org/acme/new-nonce","headers":{"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Cache-Control":["public, max-age=0, no-cache"],"Date":["Fri, 04 Apr 2025 13:11:52 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["NLny9_EduQESq5BsaC_WqVIUOP8Vb5PRATWsE-8Re1nBT0a4M3Q"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
{"level":"debug","ts":1743772313.1234367,"msg":"http request","method":"POST","url":"https://acme-v02.api.letsencrypt.org/acme/new-order","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Boulder-Requester":["2320609367"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["350"],"Content-Type":["application/json"],"Date":["Fri, 04 Apr 2025 13:11:52 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Location":["https://acme-v02.api.letsencrypt.org/acme/order/2320609367/370659333527"],"Replay-Nonce":["mjolWR0r-t_dUBjZ4pkmbwoSOf3jLV6XaM2m97Hyb9et-wdDy1s"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":201}
{"level":"debug","ts":1743772313.3882303,"msg":"http request","method":"POST","url":"https://acme-v02.api.letsencrypt.org/acme/authz/2320609367/500335459397","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Boulder-Requester":["2320609367"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["824"],"Content-Type":["application/json"],"Date":["Fri, 04 Apr 2025 13:11:53 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["NLny9_EdTSWcccBGWwG43OmcAePe1E1YKxXCDTCXcCe_D2CdrLs"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
{"level":"debug","ts":1743772313.3883786,"msg":"no solver configured","challenge_type":"http-01"}
{"level":"debug","ts":1743772313.388385,"msg":"no solver configured","challenge_type":"tls-alpn-01"}
{"level":"info","ts":1743772313.3883886,"msg":"trying to solve challenge","identifier":"test.home-lab.li","challenge_type":"dns-01","ca":"https://acme-v02.api.letsencrypt.org/directory"}
{"level":"error","ts":1743772314.5024095,"msg":"cleaning up solver","identifier":"test.home-lab.li","challenge_type":"dns-01","error":"no memory of presenting a DNS record for \"_acme-challenge.test.home-lab.li\" (usually OK if presenting also failed)","stacktrace":"github.com/mholt/acmez/v3.(*Client).solveChallenges.func1\n\tgithub.com/mholt/acmez/v3@v3.0.0/client.go:318\ngithub.com/mholt/acmez/v3.(*Client).solveChallenges\n\tgithub.com/mholt/acmez/v3@v3.0.0/client.go:363\ngithub.com/mholt/acmez/v3.(*Client).ObtainCertificate\n\tgithub.com/mholt/acmez/v3@v3.0.0/client.go:136\ngithub.com/caddyserver/certmagic.(*ACMEIssuer).doIssue\n\tgithub.com/caddyserver/certmagic@v0.21.6/acmeissuer.go:477\ngithub.com/caddyserver/certmagic.(*ACMEIssuer).Issue\n\tgithub.com/caddyserver/certmagic@v0.21.6/acmeissuer.go:399\ngithub.com/caddyserver/caddy/v2/modules/caddytls.(*ACMEIssuer).Issue\n\tgithub.com/caddyserver/caddy/v2@v2.9.1/modules/caddytls/acmeissuer.go:249\ngithub.com/caddyserver/certmagic.(*Config).obtainCert.func2\n\tgithub.com/caddyserver/certmagic@v0.21.6/config.go:626\ngithub.com/caddyserver/certmagic.doWithRetry\n\tgithub.com/caddyserver/certmagic@v0.21.6/async.go:104\ngithub.com/caddyserver/certmagic.(*Config).obtainCert\n\tgithub.com/caddyserver/certmagic@v0.21.6/config.go:700\ngithub.com/caddyserver/certmagic.(*Config).ObtainCertAsync\n\tgithub.com/caddyserver/certmagic@v0.21.6/config.go:505\ngithub.com/caddyserver/certmagic.(*Config).manageOne.func1\n\tgithub.com/caddyserver/certmagic@v0.21.6/config.go:415\ngithub.com/caddyserver/certmagic.(*jobManager).worker\n\tgithub.com/caddyserver/certmagic@v0.21.6/async.go:73"}
{"level":"debug","ts":1743772314.805724,"msg":"http request","method":"POST","url":"https://acme-v02.api.letsencrypt.org/acme/authz/2320609367/500335459397","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Boulder-Requester":["2320609367"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["828"],"Content-Type":["application/json"],"Date":["Fri, 04 Apr 2025 13:11:54 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["NLny9_Ed5F1Cf47pZzfeHFKUeF7QktuKanGymX4tgQvva7w5ZGc"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
{"level":"error","ts":1743772314.8059533,"logger":"tls.obtain","msg":"could not get certificate from issuer","identifier":"test.home-lab.li","issuer":"acme-v02.api.letsencrypt.org-directory","error":"[test.home-lab.li] solving challenges: presenting for challenge: adding temporary record for zone \"li.\": expected 1 zone, got 0 for li. (order=https://acme-v02.api.letsencrypt.org/acme/order/2320609367/370659333527) (ca=https://acme-v02.api.letsencrypt.org/directory)"}
{"level":"debug","ts":1743772314.8059952,"logger":"events","msg":"event","name":"cert_failed","id":"7225b055-8e0c-4991-8070-93d06a732fe8","origin":"tls","data":{"error":{"Err":{}},"identifier":"test.home-lab.li","issuers":["acme-v02.api.letsencrypt.org-directory"],"renewal":false}}
{"level":"info","ts":1743772314.806051,"logger":"tls.obtain","msg":"releasing lock","identifier":"test.home-lab.li"}
{"level":"error","ts":1743772314.8066485,"logger":"tls","msg":"job failed","error":"test.home-lab.li: obtaining certificate: [test.home-lab.li] Obtain: [test.home-lab.li] solving challenges: presenting for challenge: adding temporary record for zone \"li.\": expected 1 zone, got 0 for li. (order=https://acme-v02.api.letsencrypt.org/acme/order/2320609367/370659333527) (ca=https://acme-v02.api.letsencrypt.org/directory)"}

3. Caddy version:

I’m running Caddy 2.9.1

4. How I installed and ran Caddy:

  • OS/Platform: Docker container on a Linux host
  • Architecture: amd64
  • Deployment: Docker Compose

b. Command:

docker-compose up -d

c. Service/unit/compose file:

services:
  caddy:
    container_name: caddy
    build: .
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /data/caddy/caddyconf:/etc/caddy   # This is the directory, not the Caddyfile
      - /data/caddy/site:/srv
      - /data/caddy/caddy_data:/data
      - /data/caddy/caddy_config:/config
    networks:
      - alex_web

networks:
  alex_web:
    external: true

Dockerfile

FROM caddy:2-builder AS builder

RUN xcaddy build \
    --with github.com/caddy-dns/cloudflare

FROM caddy:2

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

d. My complete Caddy config:


{
    debug
}

test.home-lab.li {
    tls {
        dns cloudflare API_KEY_HERE {
            # zone home-lab.li
            # propagation_delay 60s
        }
    }
    respond "Test certificate for test.home-lab.li active"
}

I’ve also tried an alternate configuration using:

{
    acme_dns cloudflare "API_KEY_HERE"
}

but the result is the same…

What else i tried?

same error with acme_dns

{
    acme_dns cloudflare "API_KEY_HERE"
}

check if the API KEY works

curl -X GET "https://api.cloudflare.com/client/v4/zones" \
     -H "Authorization: Bearer YOUR_API_KEY_HERE" \
     -H "Content-Type: application/json"

{
  "result": [
    {
      "id": "REDACTED",
      "name": "home-lab.li",
      "status": "active",
      "paused": false,
      "type": "full",
      "development_mode": 0,
      "name_servers": [
        "alina.ns.cloudflare.com",
        "carter.ns.cloudflare.com"
      ],
      "original_name_servers": null,
      "original_registrar": null,
      "original_dnshost": null,
      "modified_on": "2025-03-25T16:00:56.672494Z",
      "created_on": "2025-03-25T14:55:19.954823Z",
      "activated_on": "2025-03-25T16:00:56.672494Z",
      "meta": {
        "step": 2,
        "custom_certificate_quota": 0,
        "page_rule_quota": 3,
        "phishing_detected": false
      },
      "owner": {
        "id": null,
        "type": "user",
        "email": null
      },
      "account": {
        "id": "REDACTED",
        "name": "underwater-way"
      },
      "tenant": {
        "id": null,
        "name": null
      },
      "tenant_unit": {
        "id": null
      },
      "permissions": [
        "#zone:read",
        "#zone_settings:read",
        "#dns_records:edit",
        "#dns_records:read"
      ],
      "plan": {
        "id": "REDACTED",
        "name": "Free Website",
        "price": 0,
        "currency": "USD",
        "frequency": "",
        "is_subscribed": false,
        "can_subscribe": false,
        "legacy_id": "free",
        "legacy_discount": false,
        "externally_managed": false
      }
    }
  ],
  "result_info": {
    "page": 1,
    "per_page": 20,
    "total_pages": 1,
    "count": 1,
    "total_count": 1
  },
  "success": true,
  "errors": [],
  "messages": []
}

i have internet on the host and in the container, tested with wget and
nslookup

wget www.cloudlfare.com
--2025-04-04 15:26:37--  http://www.cloudlfare.com/
Auflösen des Hostnamens www.cloudlfare.com (www.cloudlfare.com)… 15.197.148.33, 3.33.130.190
Verbindungsaufbau zu www.cloudlfare.com (www.cloudlfare.com)|15.197.148.33|:80 … verbunden.
HTTP-Anforderung gesendet, auf Antwort wird gewartet … 200 OK
nslookup www.cloudflare.com
Server:         10.0.30.1
Address:        10.0.30.1#53

Non-authoritative answer:
Name:   www.cloudflare.com
Address: 104.16.123.96
Name:   www.cloudflare.com
Address: 104.16.124.96
Name:   www.cloudflare.com
Address: 2606:4700::6810:7b60
Name:   www.cloudflare.com
Address: 2606:4700::6810:7c60

What is your DNS looking like?

Is “home-lab.li” your local search domain? If so, try changing it to “edge.home-lab.li” and try getting a certificate again.

I had this exact issue and couldn’t get DNS to work besides changing my local domain to the above.

1 Like
 cat /etc/resolv.conf
search home-lab.li
nameserver 10.0.30.1

I’ve now deleted the search home-lab.li line, ran ifdown and ifup, and restarted the Caddy service, but it’s still not working.

caddy  | {"level":"info","ts":1743777709.4172938,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
caddy  | {"level":"debug","ts":1743777709.4173415,"logger":"http","msg":"starting server loop","address":"[::]:80","tls":false,"http3":false}
caddy  | {"level":"warn","ts":1743777709.417358,"logger":"http","msg":"HTTP/2 skipped because it requires TLS","network":"tcp","addr":":80"}
caddy  | {"level":"warn","ts":1743777709.4173703,"logger":"http","msg":"HTTP/3 skipped because it requires TLS","network":"tcp","addr":":80"}
caddy  | {"level":"info","ts":1743777709.4173782,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
caddy  | {"level":"info","ts":1743777709.417977,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["test.home-lab.li"]}
caddy  | {"level":"info","ts":1743777709.419287,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
caddy  | {"level":"info","ts":1743777709.4193518,"msg":"serving initial configuration"}
caddy  | {"level":"info","ts":1743777709.4195905,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"d7d90c9a-a7df-42e5-97d3-b46e8a06486d","try_again":1743864109.4195888,"try_again_in":86399.999999569}
caddy  | {"level":"info","ts":1743777709.4199376,"logger":"tls","msg":"finished cleaning storage units"}
caddy  | {"level":"info","ts":1743777709.4201334,"logger":"tls.obtain","msg":"acquiring lock","identifier":"test.home-lab.li"}
caddy  | {"level":"info","ts":1743777709.453106,"logger":"tls.obtain","msg":"lock acquired","identifier":"test.home-lab.li"}
caddy  | {"level":"info","ts":1743777709.4532082,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"test.home-lab.li"}
caddy  | {"level":"debug","ts":1743777709.453232,"logger":"events","msg":"event","name":"cert_obtaining","id":"f302e07e-f063-43bf-8043-25fb6ab123e1","origin":"tls","data":{"identifier":"test.home-lab.li"}}
caddy  | {"level":"debug","ts":1743777709.4533927,"logger":"tls","msg":"created CSR","identifiers":["test.home-lab.li"],"san_dns_names":["test.home-lab.li"],"san_emails":[],"common_name":"","extra_extensions":0}
caddy  | {"level":"debug","ts":1743777709.4536183,"logger":"tls.obtain","msg":"trying issuer 1/1","issuer":"acme-v02.api.letsencrypt.org-directory"}
caddy  | {"level":"debug","ts":1743777709.453829,"logger":"tls.issuance.acme","msg":"using existing ACME account because key found in storage associated with email","email":"default","ca":"https://acme-v02.api.letsencrypt.org/directory"}
caddy  | {"level":"debug","ts":1743777709.4539263,"logger":"tls.issuance.acme","msg":"using existing ACME account because key found in storage associated with email","email":"","ca":"https://acme-v02.api.letsencrypt.org/directory"}
caddy  | {"level":"info","ts":1743777709.4539456,"logger":"tls.issuance.acme","msg":"waiting on internal rate limiter","identifiers":["test.home-lab.li"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
caddy  | {"level":"info","ts":1743777709.453949,"logger":"tls.issuance.acme","msg":"done waiting on internal rate limiter","identifiers":["test.home-lab.li"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
caddy  | {"level":"info","ts":1743777709.4539602,"logger":"tls.issuance.acme","msg":"using ACME account","account_id":"https://acme-v02.api.letsencrypt.org/acme/acct/2320609367","account_contact":[]}
caddy  | {"level":"debug","ts":1743777710.2198894,"msg":"http request","method":"GET","url":"https://acme-v02.api.letsencrypt.org/directory","headers":{"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["1042"],"Content-Type":["application/json"],"Date":["Fri, 04 Apr 2025 14:41:50 GMT"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
caddy  | {"level":"debug","ts":1743777710.2200308,"msg":"creating order","account":"https://acme-v02.api.letsencrypt.org/acme/acct/2320609367","identifiers":["test.home-lab.li"]}
caddy  | {"level":"debug","ts":1743777710.4727938,"msg":"http request","method":"HEAD","url":"https://acme-v02.api.letsencrypt.org/acme/new-nonce","headers":{"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Cache-Control":["public, max-age=0, no-cache"],"Date":["Fri, 04 Apr 2025 14:41:50 GMT"],"Link":[";rel=\"index\""],"Replay-Nonce":["nWTCjQ_H2VwWtdNfeKJhRg5bOO0EaThoEgWxs1WGDCPLTu_hyOc"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
caddy  | {"level":"debug","ts":1743777710.7832603,"msg":"http request","method":"POST","url":"https://acme-v02.api.letsencrypt.org/acme/new-order","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Boulder-Requester":["2320609367"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["350"],"Content-Type":["application/json"],"Date":["Fri, 04 Apr 2025 14:41:50 GMT"],"Link":[";rel=\"index\""],"Location":["https://acme-v02.api.letsencrypt.org/acme/order/2320609367/370679311297"],"Replay-Nonce":["nWTCjQ_HogQ7FlznUTJ6J0yU_Iq6eL20EhSUuPITs8zl4UxWals"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":201}
caddy  | {"level":"debug","ts":1743777711.0415268,"msg":"http request","method":"POST","url":"https://acme-v02.api.letsencrypt.org/acme/authz/2320609367/500365274097","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Boulder-Requester":["2320609367"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["824"],"Content-Type":["application/json"],"Date":["Fri, 04 Apr 2025 14:41:50 GMT"],"Link":[";rel=\"index\""],"Replay-Nonce":["BEwrIPHl489mrrPIWkCF5LEFGRRFnCOo9XiqihhgoaznMoh3AOE"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
caddy  | {"level":"debug","ts":1743777711.0418284,"msg":"no solver configured","challenge_type":"tls-alpn-01"}
caddy  | {"level":"debug","ts":1743777711.0418408,"msg":"no solver configured","challenge_type":"http-01"}
caddy  | {"level":"info","ts":1743777711.0418477,"msg":"trying to solve challenge","identifier":"test.home-lab.li","challenge_type":"dns-01","ca":"https://acme-v02.api.letsencrypt.org/directory"}
caddy  | {"level":"error","ts":1743777712.156991,"msg":"cleaning up solver","identifier":"test.home-lab.li","challenge_type":"dns-01","error":"no memory of presenting a DNS record for \"_acme-challenge.test.home-lab.li\" (usually OK if presenting also failed)","stacktrace":"github.com/mholt/acmez/v3.(*Client).solveChallenges.func1\n\tgithub.com/mholt/acmez/v3@v3.0.0/client.go:318\ngithub.com/mholt/acmez/v3.(*Client).solveChallenges\n\tgithub.com/mholt/acmez/v3@v3.0.0/client.go:363\ngithub.com/mholt/acmez/v3.(*Client).ObtainCertificate\n\tgithub.com/mholt/acmez/v3@v3.0.0/client.go:136\ngithub.com/caddyserver/certmagic.(*ACMEIssuer).doIssue\n\tgithub.com/caddyserver/certmagic@v0.21.6/acmeissuer.go:477\ngithub.com/caddyserver/certmagic.(*ACMEIssuer).Issue\n\tgithub.com/caddyserver/certmagic@v0.21.6/acmeissuer.go:371\ngithub.com/caddyserver/caddy/v2/modules/caddytls.(*ACMEIssuer).Issue\n\tgithub.com/caddyserver/caddy/v2@v2.9.1/modules/caddytls/acmeissuer.go:249\ngithub.com/caddyserver/certmagic.(*Config).obtainCert.func2\n\tgithub.com/caddyserver/certmagic@v0.21.6/config.go:626\ngithub.com/caddyserver/certmagic.doWithRetry\n\tgithub.com/caddyserver/certmagic@v0.21.6/async.go:104\ngithub.com/caddyserver/certmagic.(*Config).obtainCert\n\tgithub.com/caddyserver/certmagic@v0.21.6/config.go:700\ngithub.com/caddyserver/certmagic.(*Config).ObtainCertAsync\n\tgithub.com/caddyserver/certmagic@v0.21.6/config.go:505\ngithub.com/caddyserver/certmagic.(*Config).manageOne.func1\n\tgithub.com/caddyserver/certmagic@v0.21.6/config.go:415\ngithub.com/caddyserver/certmagic.(*jobManager).worker\n\tgithub.com/caddyserver/certmagic@v0.21.6/async.go:73"}
caddy  | {"level":"debug","ts":1743777712.441278,"msg":"http request","method":"POST","url":"https://acme-v02.api.letsencrypt.org/acme/authz/2320609367/500365274097","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]},"response_headers":{"Boulder-Requester":["2320609367"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["828"],"Content-Type":["application/json"],"Date":["Fri, 04 Apr 2025 14:41:52 GMT"],"Link":[";rel=\"index\""],"Replay-Nonce":["nWTCjQ_HZjS5V5SJHq4A-wnvM0k-lcnT2qD7h85e2Ir8LrVdy2E"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
caddy  | {"level":"error","ts":1743777712.4414878,"logger":"tls.obtain","msg":"could not get certificate from issuer","identifier":"test.home-lab.li","issuer":"acme-v02.api.letsencrypt.org-directory","error":"[test.home-lab.li] solving challenges: presenting for challenge: adding temporary record for zone \"li.\": expected 1 zone, got 0 for li. (order=https://acme-v02.api.letsencrypt.org/acme/order/2320609367/370679311297) (ca=https://acme-v02.api.letsencrypt.org/directory)"}

In the Caddy logs, I noticed this error:

error: [test.home-lab.li] solving challenges: presenting for challenge: adding temporary record for zone "li.": expected 1 zone, got 0 for li.

What I don’t understand is why it’s trying to add a record for the zone li.. It should be trying to add it for home-lab.li. :thinking:

Thanks a lot for your help! Any other ideas?

What I meant was on your router level. Do you use pfsense or pihole perhaps?

Change the search domain in there.

Ohh sorry ^^
For my VMs in different VLANs I use Unbound DNS – no local search domain is configured.

OPNSense has the local search domain set to "."

AdGuard doesn’t have any settings for local search domains.

Both Unbound DNS and AdGuard use DNS rewrites from *.home-lab.li to 10.0.30.10.

I think that should be fine.

What is at that IP? The rewrites might be causing the issue. If you are resolving *.home-lab.li internally, then that could be the issue.

1 Like

That IP (10.0.30.10 in VLAN 30) is my VM running on Proxmox. It hosts Docker, and inside Docker I’m running Komodo, Authentik, Caddy, and a few other services.

What’s interesting is that I had the exact same setup previously using Nginx Proxy Manager instead of Caddy, and it worked without any issues.

There’s also an OPNsense instance between Proxmox and the VM, but I’ve configured it with a rule to allow all inbound and outbound traffic for that VLAN, to rule out any firewall-related issues.

Also, I tested access via plain HTTP and it works without any problems — so it seems to be specifically related to the certificate/HTTPS part.

My experience exactly. But the problem is that when caddy tries to get the cert, and because you are resolving the domain locally, it fails.

Just so we know it is or isn’t that, can you try either turning off the local resolving of your domain, or forwarding the resolving of it to 1.1.1.1 or similar?

That way we can rule this out.

1 Like

Hey Victor,

That solved it! I deactivated the forwarding for *.home-lab.li, and now everything works perfectly.

I spent days trying nearly every workaround, so it’s a relief to see progress. However, I still need a solution for certificate renewal because I’d really like to keep my local domain set to home-lab.li. Perhaps I could disable the forwarding on OPNSense while keeping it active in AdGuard?

Also, do you know how I can trigger a renewal to test the process?

Any ideas?

thanks again a lot that u spend ur free time for me and my problem.

I usually delete the certificates to trigger a renewal.

Try this.

There are certain domains that are used when caddy renews certificates. They would be…

_acme-challenge.mydomain.ca

What I did is forward all these to 1.1.1.1 without subdomains.

I think there is one for each service like “_acme-challeng.service.domain.ca”

1 Like

Thanks so much!
I’ll give it a try.

This already helps me a lot.
I’ll test everything and share my config and settings later — then I’ll mark it as solved.

Here’s the setup I’ve configured:

I’m running two VMs — one for internal containers and one for external. Both are secured using VLANs with separate IP ranges and networks (OPNsense).

Each VM is running Caddy in a Docker container with the following configuration:

{
    acme_dns cloudflare "CLOUDFLARE_API_KEY_PLACEHOLDER"
}

Then the reverse proxies to the other containers are configured like this, all containers are in one internal docker Network
(no exposed ports except 80+443 from caddy)

komodo.example-domain.tld {
    reverse_proxy komodo:9120
}

Important note: No DNS rewrites are set in OPNsense, and no search domain is configured. My VMs use the DNS from OPNsense.

My local devices use AdGuard with DNS rewrites pointing to the IPs of the VMs.

Example:

*.example-domain.tld → 10.0.10.10
*.domain-two.int → 10.0.20.10

In OPNsense, I’ve allowed the following so that Caddy can perform DNS queries externally (which is required for ACME DNS validation):

IPv4 UDP | port DNS | VLAN30 network → *(meaning to all networks, including the internet)

With this, all certificate renewals and new certificates work perfectly!

I hope this helps other users of Caddy as well. :blush:

I’d also like to give a big shoutout to @Victor for all the help — couldn’t have done it without you!

And also, a big thanks to all the developers and contributors of Caddy for this great work.

1 Like

After some further digging, I realized I also needed internal access to services via domains like domain-two.int and others. This led me to set up Dnsmasq DNS directly in OPNsense.

I created a custom config under /usr/local/etc/dnsmasq.conf.d/dns-acme.conf with the following content:

# Redirect for _acme-challenge.*.example-domain.tld to 1.1.1.1
address=/_acme-challenge.*.example-domain.tld/1.1.1.1

# Redirect for *.example-domain.tld to the internal IP (Caddy VM)
address=/*.example-domain.tld/10.0.10.10

# Redirect for _acme-challenge.*.domain-two.int to 1.1.1.1
address=/_acme-challenge.*.domain-two.int/1.1.1.1

# Redirect for *.domain-two.int to its corresponding VM
address=/*.domain-two.int/10.0.20.10

With this in place:

  • Internal DNS lookups to services like komodo.example-domain.tld or anything under *.domain-two.int now resolve properly to the correct internal IPs.
  • ACME DNS challenges via Caddy work flawlessly since _acme-challenge queries are now properly routed to external resolvers like 1.1.1.1 instead of being intercepted internally.

Everything is now working just as intended — internal name resolution, and seamless certificate management. :rocket:

My question to @Victor:
Is this behavior with acme_dns a bug? Because I never had this issue when using Nginx Proxy Manager. If this is indeed unintended behavior, is there already a bug report open somewhere?

Hope this update helps someone dealing with similar DNS edge cases in a homelab setup!

2 Likes

I don’t know myself. One of the devs will have to weigh in and answer this one.

@matt

1 Like

Sorry, I’m not really familiar with dnsmasq – sounds like you fixed a misconfiguration, though, congratulations! And thank you for sharing the solution for the benefit of others.

I think the underlying issue is this.

When you answer *.domain.com locally, then *acme_challege.domain.com is also answered locally, which is not what we want.

So we need to filter anything with acme to be answered externally.