DNS Challenge On Duck DNS Fails with Connection Refused

1. The problem I’m having:

Obtaining the certificate always fails using DNS challenge on Duck DNS. Based on the logs apparently Caddy is trying to connect to Duck DNS over udp/53, which ends up in “connection refused” or “i/o timeout”.

Does this make sense? I’d think that it would be querying Duck over the HTTPS API to add the TXT record. This is a new Caddy setup on Docker, built with the duckdns module.

2. Error messages and/or full log output:

Caddy is requesting a domain and a star certificate. Both fail with read udp 172.19.0.2:55368->99.79.143.35:53: read: connection refused or dial tcp 99.79.143.35:53: i/o timeout.

(The actual domain is redacted to avoid publicizing my IP).

{
    "level": "info",
    "ts": 1702008471.3784668,
    "logger": "tls.obtain",
    "msg": "obtaining certificate",
    "identifier": "*.services.duckdns.org"
}{
    "level": "info",
    "ts": 1702008471.3803759,
    "logger": "tls.issuance.acme",
    "msg": "waiting on internal rate limiter",
    "identifiers": ["*.services.duckdns.org"],
    "ca": "https://acme-v02.api.letsencrypt.org/directory",
    "account": ""
}{
    "level": "info",
    "ts": 1702008471.3805563,
    "logger": "tls.issuance.acme",
    "msg": "done waiting on internal rate limiter",
    "identifiers": ["*.services.duckdns.org"],
    "ca": "https://acme-v02.api.letsencrypt.org/directory",
    "account": ""
}{
    "level": "info",
    "ts": 1702008471.3839319,
    "logger": "tls.obtain",
    "msg": "lock acquired",
    "identifier": "services.duckdns.org"
}{
    "level": "info",
    "ts": 1702008471.3843093,
    "logger": "tls.obtain",
    "msg": "obtaining certificate",
    "identifier": "services.duckdns.org"
}{
    "level": "info",
    "ts": 1702008471.3855846,
    "logger": "tls.issuance.acme",
    "msg": "waiting on internal rate limiter",
    "identifiers": ["services.duckdns.org"],
    "ca": "https://acme-v02.api.letsencrypt.org/directory",
    "account": ""
}{
    "level": "info",
    "ts": 1702008471.3856406,
    "logger": "tls.issuance.acme",
    "msg": "done waiting on internal rate limiter",
    "identifiers": ["services.duckdns.org"],
    "ca": "https://acme-v02.api.letsencrypt.org/directory",
    "account": ""
}{
    "level": "info",
    "ts": 1702008472.0595484,
    "logger": "tls.issuance.acme.acme_client",
    "msg": "trying to solve challenge",
    "identifier": "services.duckdns.org",
    "challenge_type": "dns-01",
    "ca": "https://acme-v02.api.letsencrypt.org/directory"
}{
    "level": "info",
    "ts": 1702008472.074053,
    "logger": "tls.issuance.acme.acme_client",
    "msg": "trying to solve challenge",
    "identifier": "*.services.duckdns.org",
    "challenge_type": "dns-01",
    "ca": "https://acme-v02.api.letsencrypt.org/directory"
}{
    "level": "error",
    "ts": 1702008477.4608822,
    "logger": "tls.obtain",
    "msg": "could not get certificate from issuer",
    "identifier": "*.services.duckdns.org",
    "issuer": "acme-v02.api.letsencrypt.org-directory",
    "error": "[*.services.duckdns.org] solving challenges: waiting for solver certmagic.solverWrapper to be ready: checking DNS propagation of \"_acme-challenge.services.duckdns.org\": read udp 172.19.0.2:55368->99.79.143.35:53: read: connection refused (order=https://acme-v02.api.letsencrypt.org/acme/order/...) (ca=https://acme-v02.api.letsencrypt.org/directory)"
}

3. Caddy version:

v2.7.5 h1:HoysvZkLcN2xJExEepaFHK92Qgs7xAiCFydN5x5Hs6Q=

4. How I installed and ran Caddy:

Built with a Dockerfile inline the docker-compose file. (See below).

a. System environment:

  • Ubuntu 22.04.3 LTS
  • Docker Engine 24.0.7
  • Docker Compose 2.23.3

b. Command:

sudo docker compose up -d

c. Service/unit/compose file:

docker-compose.yml:

version: "3.9"

name: proxy
services:
  caddy:
    container_name: caddy
    build:
      dockerfile_inline: |
        FROM caddy:2.7.5-builder AS builder
        RUN xcaddy build --with github.com/caddy-dns/duckdns
        FROM caddy:2.7.5
        COPY --from=builder /usr/bin/caddy /usr/bin/caddy
    restart: unless-stopped
    ports:
      - 55555:55555
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - /etc/ssl/caddy:/etc/ssl/caddy
      - ./site:/srv
      - ./data:/data
      - ./config:/config

volumes:
  data:
    external: true
  config:

d. My complete Caddy config:

*.services.duckdns.org:55555, services.duckdns.org:55555 {
        tls {
              dns duckdns 36cb16b0-3fa2-4ea4-92ab-7a0ab66cc701
        }
        
        @immich host immich
        handle @immich {
                reverse_proxy https://192.168.150.40:28376 {
                        transport http {
                                tls_server_name immich
                        }
                }
        }
}

5. Links to relevant resources:

n/a

Not sure why but this what worked eventually:

{
    email myemail@yahoo.com
}

*.services.duckdns.org:55555, services.duckdns.org:55555 {
        tls {
                issuer acme {
                        dns duckdns 36cb16b0-3fa2-4ea4-92ab-7a0ab66cc701
                        propagation_timeout -1
                }
                issuer zerossl {
                        dns duckdns 36cb16b0-3fa2-4ea4-92ab-7a0ab66cc701
                        propagation_timeout -1
                }
        }
        
        @immich host immich
        handle @immich {
                reverse_proxy https://192.168.150.40:28376 {
                        transport http {
                                tls_server_name immich
                        }
                }
        }
}

Not exactly. This is Caddy trying to make a DNS query to read your domain’s TXT records to see if it successfully wrote the ACME challenge to DuckDNS. (This is the “propagation check”). DNS queries happen over UDP on port 53.

I seems that your system is configured to use 99.79.143.35 as your DNS server. I don’t know what that is, is it your ISP’s IP address? Anyway Caddy isn’t able to connect to it for some reason.

Yeah, that turns off the propagation check, so you basically tell Caddy “don’t worry about it, I trust that the DNS will be properly updated”. Most of the time, that’s true. The propagation check isn’t necessary, we just do it as a sanity check to avoid telling the ACME issuer we’re ready for it to look for the TXT record when it might not actually be ready yet. But with DuckDNS it’s pretty much instantaneous so there’s no need to wait for propagation.

:warning:

You posted your DuckDNS token to the forums… that’s not good, that means anyone could use it to update your DNS to point somewhere else. You can refresh your token on the DuckDNS website (click the 3 lines next to your email in the top-right, then click recreate token).

1 Like

Thanks for the info.

The token is a fake one. I used it to express my config as clearly as possible )

99.79.143.35 is the ip for duckdns.org. That’s why I wonder why Caddy is querying it as a DNS server.

1 Like

Well, DuckDNS is also a DNS server, that’s how it actually does its job. dig duckdns.org does show 99.79.143.35 as one of its name servers.

But I don’t know why your system isn’t connecting. Could be somekind of network misconfiguration on your end.

Or you could just use a different DNS resolver with resolvers 1.1.1.1 to use Cloudflare’s for example (in your tls config in Caddy).

Knowing that my network must not have been the problem (at least my LAN), today I decided to try with a simpler config, and it worked. I deleted the certs and Caddy was able to obtain them from Let’s Encrypt immediately.

For completeness, this is the last config:

{
        email email@yahoo.com
        log default {
                output stdout
                format console {
                        time_format iso8601
                        time_local
                }
        }
}

*.services.duckdns.org:55555, services.duckdns.org:55555 {
        tls {
             dns duckdns 36cb16b0-3fa2-4ea4-92ab-7a0ab66cc701
        }

        @immich host immich.services.duckdns.org
        handle @immich {
                reverse_proxy https://192.168.150.40:28376 {
                        transport http {
                                tls_server_name immich
                        }
                }
        }

        handle {
                abort
        }

}

Maybe it’s the inclusion of the email global option or last night I was just unlucky and having connectivity problems with Duck DNS.

By the way, should I add the port to the host matcher?

:man_shrugging:

No, the host matcher splits the host:port from the Host header before matching.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.