DNS-01 file not being written to Cloudflare

1. The problem I’m having:

I’m no longer able to automatically get a new SSL cert for my subdomains using DNS-01 challenge with Cloudflare.

Caddy can’t place the DNS txt file in Cloudflare DNS. I’m can place it manually using my Cloudflare API Token and CURL on a shell from inside my docker container. The API token is available as an env variable within the docker container. I’ve tried resetting my API token. The token has the following settings:

  • Zone - Zone - Read
  • Zone - DNS - Edit
  • Include - Specific Zone - mydomain

I’m unsure if this is related, my subdomains are (by design) somewhat accessible outside my network through a Cloudflare tunnel. When inside my network, my router hijacks mydomain’s DNS and points it to the server running Caddy.

~$ curl -vL nextcloud.mydomain
* Host nextcloud.mydomain:80 was resolved.
* IPv6: (none)
* IPv4: 192.168.1.229
*   Trying 192.168.1.229:80...
* Connected to nextcloud.mydomain (192.168.1.229) port 80
> GET / HTTP/1.1
> Host: nextcloud.mydomain
> User-Agent: curl/8.9.1
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://nextcloud.mydomain/
< Server: Caddy
< Date: Tue, 20 May 2025 19:26:34 GMT
< Content-Length: 0
< 
* shutting down connection #0
* Clear auth, redirects to port from 80 to 443
* Issue another request to this URL: 'https://nextcloud.mydomain/'
* Host nextcloud.mydomain:443 was resolved.
* IPv6: (none)
* IPv4: 192.168.1.229
*   Trying 192.168.1.229:443...
* Connected to nextcloud.mydomain (192.168.1.229) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /home/aryeh/anaconda3/ssl/cacert.pem
*  CApath: none
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (OUT), TLS alert, certificate expired (557):
* SSL certificate problem: certificate has expired
* closing connection #1
curl: (60) SSL certificate problem: certificate has expired
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the webpage mentioned above.

2. Error messages and/or full log output:

caddy-caddy-1  | {"level":"debug","ts":1747768586.8816273,"msg":"http request","method":"POST","url":"https://acme-v02.api.letsencrypt.org/acme/authz/2012260467/523283614547","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.10.0 CertMagic acmez (linux; amd64)"]},"response_headers":{"Boulder-Requester":["2012260467"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["838"],"Content-Type":["application/json"],"Date":["Tue, 20 May 2025 19:16:26 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["4zqsHs_ShJNXQL-n3qtXN6TLV6SrJsg-pGrKnEUaSNUwmMTX7nk"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
caddy-caddy-1  | {"level":"error","ts":1747768586.881801,"logger":"tls.renew","msg":"could not get certificate from issuer","identifier":"librespeed.mydomain","issuer":"acme-v02.api.letsencrypt.org-directory","error":"[librespeed.mydomain] solving challenges: presenting for challenge: adding temporary record for zone \"net.\": expected 1 zone, got 0 for net. (order=https://acme-v02.api.letsencrypt.org/acme/order/2012260467/386039220147) (ca=https://acme-v02.api.letsencrypt.org/directory)"}
caddy-caddy-1  | {"level":"debug","ts":1747768586.8820987,"logger":"tls.issuance.acme","msg":"using existing ACME account because key found in storage associated with email","email":"myemail","ca":"https://acme.zerossl.com/v2/DV90"}
caddy-caddy-1  | {"level":"info","ts":1747768586.882133,"logger":"tls.issuance.acme","msg":"waiting on internal rate limiter","identifiers":["librespeed.mydomain"],"ca":"https://acme.zerossl.com/v2/DV90","account":"myemail"}
caddy-caddy-1  | {"level":"info","ts":1747768586.8821466,"logger":"tls.issuance.acme","msg":"done waiting on internal rate limiter","identifiers":["librespeed.mydomain"],"ca":"https://acme.zerossl.com/v2/DV90","account":"myemail"}
caddy-caddy-1  | {"level":"info","ts":1747768586.8821619,"logger":"tls.issuance.acme","msg":"using ACME account","account_id":"https://acme.zerossl.com/v2/DV90/account/wEyCKX3IJIqlInBE2rOcKQ","account_contact":["mailto:myemail"]}
caddy-caddy-1  | {"level":"debug","ts":1747768587.3721623,"msg":"http request","method":"GET","url":"https://acme.zerossl.com/v2/DV90","headers":{"User-Agent":["Caddy/2.10.0 CertMagic acmez (linux; amd64)"]},"response_headers":{"Access-Control-Allow-Origin":["*"],"Content-Length":["712"],"Content-Type":["application/json"],"Date":["Tue, 20 May 2025 19:16:27 GMT"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]},"status_code":200}
caddy-caddy-1  | {"level":"debug","ts":1747768587.3725502,"msg":"creating order","account":"https://acme.zerossl.com/v2/DV90/account/wEyCKX3IJIqlInBE2rOcKQ","identifiers":["librespeed.mydomain"]}
caddy-caddy-1  | {"level":"error","ts":1747768587.4968185,"msg":"cleaning up solver","identifier":"nextcloud.mydomain","challenge_type":"dns-01","error":"no memory of presenting a DNS record for \"_acme-challenge.nextcloud.mydomain\" (usually OK if presenting also failed)","stacktrace":"github.com/mholt/acmez/v3.(*Client).solveChallenges.func1\n\tgithub.com/mholt/acmez/v3@v3.1.2/client.go:318\ngithub.com/mholt/acmez/v3.(*Client).solveChallenges\n\tgithub.com/mholt/acmez/v3@v3.1.2/client.go:363\ngithub.com/mholt/acmez/v3.(*Client).ObtainCertificate\n\tgithub.com/mholt/acmez/v3@v3.1.2/client.go:136\ngithub.com/caddyserver/certmagic.(*ACMEIssuer).doIssue\n\tgithub.com/caddyserver/certmagic@v0.23.0/acmeissuer.go:489\ngithub.com/caddyserver/certmagic.(*ACMEIssuer).Issue\n\tgithub.com/caddyserver/certmagic@v0.23.0/acmeissuer.go:382\ngithub.com/caddyserver/caddy/v2/modules/caddytls.(*ACMEIssuer).Issue\n\tgithub.com/caddyserver/caddy/v2@v2.10.0/modules/caddytls/acmeissuer.go:288\ngithub.com/caddyserver/certmagic.(*Config).renewCert.func2\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:906\ngithub.com/caddyserver/certmagic.doWithRetry\n\tgithub.com/caddyserver/certmagic@v0.23.0/async.go:104\ngithub.com/caddyserver/certmagic.(*Config).renewCert\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:982\ngithub.com/caddyserver/certmagic.(*Config).RenewCertAsync\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:768\ngithub.com/caddyserver/certmagic.(*Config).manageOne.func2\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:469\ngithub.com/caddyserver/certmagic.(*jobManager).worker\n\tgithub.com/caddyserver/certmagic@v0.23.0/async.go:73"}
caddy-caddy-1  | {"level":"debug","ts":1747768587.7227437,"msg":"http request","method":"POST","url":"https://acme-v02.api.letsencrypt.org/acme/authz/2012260467/523283614827","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.10.0 CertMagic acmez (linux; amd64)"]},"response_headers":{"Boulder-Requester":["2012260467"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["837"],"Content-Type":["application/json"],"Date":["Tue, 20 May 2025 19:16:27 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["4zqsHs_Suje7T1zaMHK3Bh9wbnZtslmfY58_Dy_ZX7UIZcW8uAo"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
caddy-caddy-1  | {"level":"error","ts":1747768587.7235277,"logger":"tls.renew","msg":"could not get certificate from issuer","identifier":"nextcloud.mydomain","issuer":"acme-v02.api.letsencrypt.org-directory","error":"[nextcloud.mydomain] solving challenges: presenting for challenge: adding temporary record for zone \"net.\": expected 1 zone, got 0 for net. (order=https://acme-v02.api.letsencrypt.org/acme/order/2012260467/386039220307) (ca=https://acme-v02.api.letsencrypt.org/directory)"}
caddy-caddy-1  | {"level":"debug","ts":1747768587.7250264,"logger":"tls.issuance.acme","msg":"using existing ACME account because key found in storage associated with email","email":"myemail","ca":"https://acme.zerossl.com/v2/DV90"}
caddy-caddy-1  | {"level":"info","ts":1747768587.7251,"logger":"tls.issuance.acme","msg":"waiting on internal rate limiter","identifiers":["nextcloud.mydomain"],"ca":"https://acme.zerossl.com/v2/DV90","account":"myemail"}
caddy-caddy-1  | {"level":"info","ts":1747768587.725189,"logger":"tls.issuance.acme","msg":"done waiting on internal rate limiter","identifiers":["nextcloud.mydomain"],"ca":"https://acme.zerossl.com/v2/DV90","account":"myemail"}
caddy-caddy-1  | {"level":"info","ts":1747768587.7252839,"logger":"tls.issuance.acme","msg":"using ACME account","account_id":"https://acme.zerossl.com/v2/DV90/account/wEyCKX3IJIqlInBE2rOcKQ","account_contact":["mailto:myemail"]}
caddy-caddy-1  | {"level":"debug","ts":1747768587.7253804,"msg":"creating order","account":"https://acme.zerossl.com/v2/DV90/account/wEyCKX3IJIqlInBE2rOcKQ","identifiers":["nextcloud.mydomain"]}
caddy-caddy-1  | {"level":"debug","ts":1747768587.8064494,"msg":"http request","method":"HEAD","url":"https://acme.zerossl.com/v2/DV90/newNonce","headers":{"User-Agent":["Caddy/2.10.0 CertMagic acmez (linux; amd64)"]},"response_headers":{"Access-Control-Allow-Origin":["*"],"Cache-Control":["max-age=0, no-cache, no-store"],"Content-Type":["application/octet-stream"],"Date":["Tue, 20 May 2025 19:16:27 GMT"],"Link":["<https://acme.zerossl.com/v2/DV90>;rel=\"index\""],"Replay-Nonce":["qCVEOcIxt67iamvbaEgMVybBMbnYukUPFriZLbXTkYc"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]},"status_code":200}
caddy-caddy-1  | {"level":"debug","ts":1747768588.0764358,"msg":"http request","method":"HEAD","url":"https://acme.zerossl.com/v2/DV90/newNonce","headers":{"User-Agent":["Caddy/2.10.0 CertMagic acmez (linux; amd64)"]},"response_headers":{"Access-Control-Allow-Origin":["*"],"Cache-Control":["max-age=0, no-cache, no-store"],"Content-Type":["application/octet-stream"],"Date":["Tue, 20 May 2025 19:16:28 GMT"],"Link":["<https://acme.zerossl.com/v2/DV90>;rel=\"index\""],"Replay-Nonce":["8B8qs2816G-FSWK5oDvqjMZIjG_R3RD_6GhtwfNDhWc"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]},"status_code":200}
caddy-caddy-1  | {"level":"debug","ts":1747768588.24618,"msg":"http request","method":"POST","url":"https://acme.zerossl.com/v2/DV90/newOrder","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.10.0 CertMagic acmez (linux; amd64)"]},"response_headers":{"Access-Control-Allow-Origin":["*"],"Cache-Control":["max-age=0, no-cache, no-store"],"Content-Length":["288"],"Content-Type":["application/json"],"Date":["Tue, 20 May 2025 19:16:28 GMT"],"Location":["https://acme.zerossl.com/v2/DV90/order/5FM2QWiHtanwFGXquouqqg"],"Replay-Nonce":["xGJCpfUVeJSNsb5uNFMiS5W8ynHUcO5p9HY5Fii2WTg"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]},"status_code":201}
caddy-caddy-1  | {"level":"error","ts":1747768588.2679534,"msg":"cleaning up solver","identifier":"jellyfin.mydomain","challenge_type":"dns-01","error":"no memory of presenting a DNS record for \"_acme-challenge.jellyfin.mydomain\" (usually OK if presenting also failed)","stacktrace":"github.com/mholt/acmez/v3.(*Client).solveChallenges.func1\n\tgithub.com/mholt/acmez/v3@v3.1.2/client.go:318\ngithub.com/mholt/acmez/v3.(*Client).solveChallenges\n\tgithub.com/mholt/acmez/v3@v3.1.2/client.go:363\ngithub.com/mholt/acmez/v3.(*Client).ObtainCertificate\n\tgithub.com/mholt/acmez/v3@v3.1.2/client.go:136\ngithub.com/caddyserver/certmagic.(*ACMEIssuer).doIssue\n\tgithub.com/caddyserver/certmagic@v0.23.0/acmeissuer.go:489\ngithub.com/caddyserver/certmagic.(*ACMEIssuer).Issue\n\tgithub.com/caddyserver/certmagic@v0.23.0/acmeissuer.go:382\ngithub.com/caddyserver/caddy/v2/modules/caddytls.(*ACMEIssuer).Issue\n\tgithub.com/caddyserver/caddy/v2@v2.10.0/modules/caddytls/acmeissuer.go:288\ngithub.com/caddyserver/certmagic.(*Config).renewCert.func2\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:906\ngithub.com/caddyserver/certmagic.doWithRetry\n\tgithub.com/caddyserver/certmagic@v0.23.0/async.go:104\ngithub.com/caddyserver/certmagic.(*Config).renewCert\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:982\ngithub.com/caddyserver/certmagic.(*Config).RenewCertAsync\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:768\ngithub.com/caddyserver/certmagic.(*Config).manageOne.func2\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:469\ngithub.com/caddyserver/certmagic.(*jobManager).worker\n\tgithub.com/caddyserver/certmagic@v0.23.0/async.go:73"}
caddy-caddy-1  | {"level":"debug","ts":1747768588.5188699,"msg":"http request","method":"POST","url":"https://acme-v02.api.letsencrypt.org/acme/authz/2012260467/523283615317","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.10.0 CertMagic acmez (linux; amd64)"]},"response_headers":{"Boulder-Requester":["2012260467"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["836"],"Content-Type":["application/json"],"Date":["Tue, 20 May 2025 19:16:28 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["4zqsHs_SPWWBA0Rrdv51GTjnBZl6nhjsCVH27Y3q1IaxKe1ZGBo"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
caddy-caddy-1  | {"level":"error","ts":1747768588.5191581,"logger":"tls.renew","msg":"could not get certificate from issuer","identifier":"jellyfin.mydomain","issuer":"acme-v02.api.letsencrypt.org-directory","error":"[jellyfin.mydomain] solving challenges: presenting for challenge: adding temporary record for zone \"net.\": expected 1 zone, got 0 for net. (order=https://acme-v02.api.letsencrypt.org/acme/order/2012260467/386039220517) (ca=https://acme-v02.api.letsencrypt.org/directory)"}
caddy-caddy-1  | {"level":"debug","ts":1747768588.5197053,"logger":"tls.issuance.acme","msg":"using existing ACME account because key found in storage associated with email","email":"myemail","ca":"https://acme.zerossl.com/v2/DV90"}
caddy-caddy-1  | {"level":"info","ts":1747768588.519732,"logger":"tls.issuance.acme","msg":"waiting on internal rate limiter","identifiers":["jellyfin.mydomain"],"ca":"https://acme.zerossl.com/v2/DV90","account":"myemail"}
caddy-caddy-1  | {"level":"info","ts":1747768588.5197532,"logger":"tls.issuance.acme","msg":"done waiting on internal rate limiter","identifiers":["jellyfin.mydomain"],"ca":"https://acme.zerossl.com/v2/DV90","account":"myemail"}
caddy-caddy-1  | {"level":"info","ts":1747768588.5198073,"logger":"tls.issuance.acme","msg":"using ACME account","account_id":"https://acme.zerossl.com/v2/DV90/account/wEyCKX3IJIqlInBE2rOcKQ","account_contact":["mailto:myemail"]}
caddy-caddy-1  | {"level":"debug","ts":1747768588.519838,"msg":"creating order","account":"https://acme.zerossl.com/v2/DV90/account/wEyCKX3IJIqlInBE2rOcKQ","identifiers":["jellyfin.mydomain"]}
caddy-caddy-1  | {"level":"debug","ts":1747768588.622715,"msg":"http request","method":"POST","url":"https://acme.zerossl.com/v2/DV90/newOrder","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.10.0 CertMagic acmez (linux; amd64)"]},"response_headers":{"Access-Control-Allow-Origin":["*"],"Cache-Control":["max-age=0, no-cache, no-store"],"Content-Length":["287"],"Content-Type":["application/json"],"Date":["Tue, 20 May 2025 19:16:28 GMT"],"Location":["https://acme.zerossl.com/v2/DV90/order/333cy7zHZa1RCcnxdm808g"],"Replay-Nonce":["niEBqEx3_45dXYhYKpIgR85gvhz1GiKXy7W55cdruEc"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]},"status_code":201}
caddy-caddy-1  | {"level":"error","ts":1747768589.1523464,"msg":"cleaning up solver","identifier":"immich.mydomain","challenge_type":"dns-01","error":"no memory of presenting a DNS record for \"_acme-challenge.immich.mydomain\" (usually OK if presenting also failed)","stacktrace":"github.com/mholt/acmez/v3.(*Client).solveChallenges.func1\n\tgithub.com/mholt/acmez/v3@v3.1.2/client.go:318\ngithub.com/mholt/acmez/v3.(*Client).solveChallenges\n\tgithub.com/mholt/acmez/v3@v3.1.2/client.go:363\ngithub.com/mholt/acmez/v3.(*Client).ObtainCertificate\n\tgithub.com/mholt/acmez/v3@v3.1.2/client.go:136\ngithub.com/caddyserver/certmagic.(*ACMEIssuer).doIssue\n\tgithub.com/caddyserver/certmagic@v0.23.0/acmeissuer.go:489\ngithub.com/caddyserver/certmagic.(*ACMEIssuer).Issue\n\tgithub.com/caddyserver/certmagic@v0.23.0/acmeissuer.go:382\ngithub.com/caddyserver/caddy/v2/modules/caddytls.(*ACMEIssuer).Issue\n\tgithub.com/caddyserver/caddy/v2@v2.10.0/modules/caddytls/acmeissuer.go:288\ngithub.com/caddyserver/certmagic.(*Config).renewCert.func2\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:906\ngithub.com/caddyserver/certmagic.doWithRetry\n\tgithub.com/caddyserver/certmagic@v0.23.0/async.go:104\ngithub.com/caddyserver/certmagic.(*Config).renewCert\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:982\ngithub.com/caddyserver/certmagic.(*Config).RenewCertAsync\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:768\ngithub.com/caddyserver/certmagic.(*Config).manageOne.func2\n\tgithub.com/caddyserver/certmagic@v0.23.0/config.go:469\ngithub.com/caddyserver/certmagic.(*jobManager).worker\n\tgithub.com/caddyserver/certmagic@v0.23.0/async.go:73"}
caddy-caddy-1  | {"level":"debug","ts":1747768589.1909342,"msg":"http request","method":"POST","url":"https://acme.zerossl.com/v2/DV90/authz/ZDG9ofTjmGVX1aMQPM64sg","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.10.0 CertMagic acmez (linux; amd64)"]},"response_headers":{"Access-Control-Allow-Origin":["*"],"Cache-Control":["max-age=0, no-cache, no-store"],"Content-Length":["455"],"Content-Type":["application/json"],"Date":["Tue, 20 May 2025 19:16:29 GMT"],"Link":["<https://acme.zerossl.com/v2/DV90>;rel=\"index\""],"Replay-Nonce":["2NcD_cU5iYotWZ4xLrawhWA0vpgT7s1WhjiEcwUbwa4"],"Retry-After":["5"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]},"status_code":200}
caddy-caddy-1  | {"level":"info","ts":1747768589.1915176,"msg":"trying to solve challenge","identifier":"nextcloud.mydomain","challenge_type":"dns-01","ca":"https://acme.zerossl.com/v2/DV90"}
caddy-caddy-1  | {"level":"debug","ts":1747768589.422083,"msg":"http request","method":"POST","url":"https://acme-v02.api.letsencrypt.org/acme/authz/2012260467/523283615597","headers":{"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.10.0 CertMagic acmez (linux; amd64)"]},"response_headers":{"Boulder-Requester":["2012260467"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["834"],"Content-Type":["application/json"],"Date":["Tue, 20 May 2025 19:16:29 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["NySGY0K7A5JK-JohhS8MWi3-jvMu91JUNZSo6_FiQtt9mDysVbE"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]},"status_code":200}
caddy-caddy-1  | {"level":"error","ts":1747768589.4227195,"logger":"tls.renew","msg":"could not get certificate from issuer","identifier":"immich.mydomain","issuer":"acme-v02.api.letsencrypt.org-directory","error":"[immich.mydomain] solving challenges: presenting for challenge: adding temporary record for zone \"net.\": expected 1 zone, got 0 for net. (order=https://acme-v02.api.letsencrypt.org/acme/order/2012260467/386039220807) (ca=https://acme-v02.api.letsencrypt.org/directory)"}
caddy-caddy-1  | {"level":"debug","ts":1747768589.4242842,"logger":"tls.issuance.acme","msg":"using existing ACME account because key found in storage associated with email","email":"myemail","ca":"https://acme.zerossl.com/v2/DV90"}

3. Caddy version:

docker compose exec caddy caddy version
v2.10.0 h1:fonubSaQKF1YANl8TXqGcn4IbIRUDdfAkpcsfI/vX5U=

4. How I installed and ran Caddy:

a. System environment:

Ubuntu 22.04 Server
Intel

docker version

Client: Docker Engine - Community
 Version:           28.1.1
 API version:       1.49
 Go version:        go1.23.8
 Git commit:        4eba377
 Built:             Fri Apr 18 09:52:10 2025
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          28.1.1
  API version:      1.49 (minimum version 1.24)
  Go version:       go1.23.8
  Git commit:       01f442b
  Built:            Fri Apr 18 09:52:10 2025
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.7.27
  GitCommit:        05044ec0a9a75232cad458027ca83437aae3f4da
 runc:
  Version:          1.2.5
  GitCommit:        v1.2.5-0-g59923ef
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

docker compose version
Docker Compose version v2.18.1

b. Command:

docker compose up -d

c. Service/unit/compose file:

services:
  caddy:
    image: ghcr.io/caddybuilds/caddy-cloudflare:latest
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - $PWD/Caddyfile:/etc/caddy/Caddyfile
      - $PWD/site:/srv
      - caddy_data:/data
      - caddy_config:/config
    environment:
      - CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}
    networks:
      - net
      
volumes:
  caddy_data:
    external: true
  caddy_config:

networks:
  net:
    external: true

d. My complete Caddy config:

Caddyfile

{
  email myemail
  acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
  debug
}


nextcloud.mydomain {
  reverse_proxy nextcloud-app-1:80
}

immich.mydomain {
  reverse_proxy immich_server:2283
}

gitea.mydomain {
  reverse_proxy gitea:3000
}

kuma.mydomain {
  reverse_proxy uptime-kuma:3001
}

librespeed.mydomain {
  reverse_proxy librespeed:80
}

ha.mydomain {
  reverse_proxy 192.168.1.105:8123
}

jellyfin.mydomain {
  reverse_proxy jellyfin:8096
}

5. Links to relevant resources:

Not sure if it causing any problems, but I have some of the subdomains proxyed through a Cloudflare tunnel for access outside my network.

It doesn’t matter, the DNS-01 challenge only requires that you can set DNS records, the issuer (LetsEncrypt, ZeroSSL etc) will not try to connect to your web server.

It looks like Caddy can’t issue the certificates you asked for, though I didn’t understand why from the logs. But hijacking the local DNS might be a problem.

1 Like

I’ve modified my router settings, and have been able to get the certs working, but now have some side effects.

Previously I had my domain listed in the Resolve these locally in my router, which probably prevented Caddy from finding the DNS TXT file in Cloudflare. Now that I removed my domain from Resolve these locally I can get certs. The problem is when I lookup the DNS of my domain, I get the local ipv4 of my server (which is good), but I also get the ipv6 records of my Cloduflare tunnel (which is bad, I don’t want to go through my CF tunnel when inside my LAN).

I have added resolvers 1.1.1.1 to the tls section of my Caddyfile, but it is only respected when I remove my domain from the Resolve these locally list in my router.

Is there a good way to deal with my split-dns setup so that my DNS TXT file gets checked in Cloudflare, but every other request for my domain gets handled locally?

1 Like

Is there a way to use DoH in the Caddy resolvers? That might get around my routers DNS hijacking

It sounds like your router’s DNS handling isn’t very good. Can you replace it with something better, or upgrade it to OpenWRT? dnsmasq on OpenWRT will let you overwrite specific records so your DNS-01 will still work but you can have internal IPs.

Alternatively use a different hostname for internal and external.

I have Openwrt on my router. It looks like the setting that is causing the issues is Resolve these locally where I include lan and my domain. I checked wireshark and Caddy is failing on the SOA DNS record checks. My router is returning OPT instead of the Cloudflare DNS server. (the check for the txt DNS file will probably also fail).

I have my domain in the Resolve these locally because if I don’t my domain resolves to the local ipv4 address (good), but also the ipv6 address for the cloudflare tunnel I use outside my house (bad).

Is there a way to hijack the A and AAAA DNS records, but let the SOA and TXT DNS records through for my domain?

Sure, whatever you put in the Static Leases or Hostnames in the OpenWRT config will override the public DNS, everything else will pass through. Especially when they aren’t for the same host within the domain.

Where do you see Resolve these locally in OpenWRT? I don’t think I’ve ever heard of that setting.

Network → DHCP and DNS → General

It is the second option on the page.

From the command line you can find it at
/etc/config/dhcp

config dnsmasq
    option local '/lan/mydomain/'

I just have the default /lan/ (unused) in that field. I do have my domain in the next field though.