Struggling with DNS challenge for local homelab

1. The problem I’m having:

I have the following setup at home:

  • a bunch of docker containers running on various hosts
  • a pihole that acts as my DNS server with ad blocking
  • a caddy running on one of the hosts that acts as a reverse proxy

I want to enable HTTPS certs for my local services using a DNS challenge for a domain name that I own but it is not working.

I have changed the domain here to replace the real one. I would like to have multiple services proxied so I can access then through nice URLs in my local network without having to remember IP addresses and port numbers, hence the the attempt to get a wildcart cert for all services.

This is my log I get when I run caddy, even when I let caddy run it just get the same error from letsencrypt.

2. Error messages and/or full log output:

2025/03/19 16:16:55.028 INFO    using config from file  {"file": "Caddyfile"}
2025/03/19 16:16:55.032 INFO    adapted config to JSON  {"adapter": "caddyfile"}
2025/03/19 16:16:55.035 INFO    admin   admin endpoint started  {"address": "localhost:2019", "enforce_origin": false, "origins": ["//localhost:2019", "//[::1]:2019", "//127.0.0.1:2019"]}
2025/03/19 16:16:55.035 INFO    tls.cache.maintenance   started background certificate maintenance      {"cache": "0x400052f380"}
2025/03/19 16:16:55.035 INFO    http.auto_https server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2025/03/19 16:16:55.036 INFO    http.auto_https enabling automatic HTTP->HTTPS redirects        {"server_name": "srv0"}
2025/03/19 16:16:55.038 INFO    http    enabling HTTP/3 listener        {"addr": ":443"}
2025/03/19 16:16:55.038 INFO    http.log        server running  {"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2025/03/19 16:16:55.039 WARN    http    HTTP/2 skipped because it requires TLS  {"network": "tcp", "addr": ":80"}
2025/03/19 16:16:55.039 WARN    http    HTTP/3 skipped because it requires TLS  {"network": "tcp", "addr": ":80"}
2025/03/19 16:16:55.039 INFO    http.log        server running  {"name": "remaining_auto_https_redirects", "protocols": ["h1", "h2", "h3"]}
2025/03/19 16:16:55.039 INFO    http    enabling automatic TLS certificate management   {"domains": ["*.mydomain.com"]}
2025/03/19 16:16:55.046 INFO    autosaved config (load with --resume flag)      {"file": "/root/.config/caddy/autosave.json"}
2025/03/19 16:16:55.046 INFO    serving initial configuration
2025/03/19 16:16:55.047 INFO    tls     storage cleaning happened too recently; skipping for now        {"storage": "FileStorage:/root/.local/share/caddy", "instance": "322ddd3f-b5a1-4b63-a8d5-6b829d41115b", "try_again": "2025/03/20 16:16:55.047", "try_again_in": 86399.999997981}
2025/03/19 16:16:55.047 INFO    tls     finished cleaning storage units
2025/03/19 16:16:55.055 INFO    tls.obtain      acquiring lock  {"identifier": "*.mydomain.com"}
2025/03/19 16:16:55.066 INFO    tls.obtain      lock acquired   {"identifier": "*.mydomain.com"}
2025/03/19 16:16:55.066 INFO    tls.obtain      obtaining certificate   {"identifier": "*.mydomain.com"}
2025/03/19 16:16:55.069 INFO    tls.issuance.acme       waiting on internal rate limiter        {"identifiers": ["*.mydomain.com"], "ca": "https://acme-v02.api.letsencrypt.org/directory", "account": "my_email@mail.com"}
2025/03/19 16:16:55.069 INFO    tls.issuance.acme       done waiting on internal rate limiter   {"identifiers": ["*.mydomain.com"], "ca": "https://acme-v02.api.letsencrypt.org/directory", "account": "my_email@mail.com"}
2025/03/19 16:16:55.069 INFO    tls.issuance.acme       using ACME account      {"account_id": "https://acme-v02.api.letsencrypt.org/acme/acct/*********", "account_contact": ["mailto:my_email@mail.com"]}
2025/03/19 16:16:55.838 INFO    trying to solve challenge       {"identifier": "*.mydomain.com", "challenge_type": "dns-01", "ca": "https://acme-v02.api.letsencrypt.org/directory"}
2025/03/19 16:16:56.487 ERROR   cleaning up solver      {"identifier": "*.mydomain.com", "challenge_type": "dns-01", "error": "no memory of presenting a DNS record for \"_acme-challenge.mydomain.com\" (usually OK if presenting also failed)"}
github.com/mholt/acmez/v3.(*Client).solveChallenges.func1
        github.com/mholt/acmez/v3@v3.0.0/client.go:318
github.com/mholt/acmez/v3.(*Client).solveChallenges
        github.com/mholt/acmez/v3@v3.0.0/client.go:363
github.com/mholt/acmez/v3.(*Client).ObtainCertificate
        github.com/mholt/acmez/v3@v3.0.0/client.go:136
github.com/caddyserver/certmagic.(*ACMEIssuer).doIssue
        github.com/caddyserver/certmagic@v0.21.6/acmeissuer.go:477
github.com/caddyserver/certmagic.(*ACMEIssuer).Issue
        github.com/caddyserver/certmagic@v0.21.6/acmeissuer.go:371
github.com/caddyserver/caddy/v2/modules/caddytls.(*ACMEIssuer).Issue
        github.com/caddyserver/caddy/v2@v2.9.1/modules/caddytls/acmeissuer.go:249
github.com/caddyserver/certmagic.(*Config).obtainCert.func2
        github.com/caddyserver/certmagic@v0.21.6/config.go:626
github.com/caddyserver/certmagic.doWithRetry
        github.com/caddyserver/certmagic@v0.21.6/async.go:104
github.com/caddyserver/certmagic.(*Config).obtainCert
        github.com/caddyserver/certmagic@v0.21.6/config.go:700
github.com/caddyserver/certmagic.(*Config).ObtainCertAsync
        github.com/caddyserver/certmagic@v0.21.6/config.go:505
github.com/caddyserver/certmagic.(*Config).manageOne.func1
        github.com/caddyserver/certmagic@v0.21.6/config.go:415
github.com/caddyserver/certmagic.(*jobManager).worker
        github.com/caddyserver/certmagic@v0.21.6/async.go:73
2025/03/19 16:16:56.642 ERROR   tls.obtain      could not get certificate from issuer   {"identifier": "*.mydomain.com", "issuer": "acme-v02.api.letsencrypt.org-directory", "error": "[*.mydomain.com] solving challenges: presenting for challenge: adding temporary record for zone \"mydomain.com.\": Invalid http response status, {\"status\":\"ERROR\",\"message\":\"Invalid API key. (001)\"} (order=https://acme-v02.api.letsencrypt.org/acme/order/******/*******) (ca=https://acme-v02.api.letsencrypt.org/directory)"}
2025/03/19 16:16:56.642 ERROR   tls.obtain      will retry      {"error": "[*.mydomain.com] Obtain: [*.mydomain.com] solving challenges: presenting for challenge: adding temporary record for zone \"mydomain.com.\": Invalid http response status, {\"status\":\"ERROR\",\"message\":\"Invalid API key. (001)\"} (order=https://acme-v02.api.letsencrypt.org/acme/order/******/*******) (ca=https://acme-v02.api.letsencrypt.org/directory)", "attempt": 1, "retrying_in": 60, "elapsed": 1.576001522, "max_duration": 2592000}

3. Caddy version:

caddy --version
v2.9.1 h1:OEYiZ7DbCzAWVb6TNEkjRcSCRGHVoZsJinoDR/n9oaY=

4. How I installed and ran Caddy:

Downloaded a custom build from caddy site to enable my dns provider.

a. System environment:

PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

b. Command:

caddy run --config Caddyfile

d. My complete Caddy config:

*.mydomain.com {
	tls {
		dns porkbun {
			api_key KEY
			api_secret_key SECRET
		}
	}

	@pihole host pihole.mydomain.com
	handle @pihole {
		reverse_proxy 192.168.1.101:8443
	}
}

5. Links to relevant resources:

Nothing.

Your error clearly says that it is an invalid API key. Make sure that it is correct.

Yeah, I will have to check on that, I could see some acme records being created so I am not sure why this is failing.

Okay, I have regenerated a new API key and things are working fine now.

1 Like