.local domains and public CA

1. Caddy version (caddy version):

v2.4.5 h1:P1mRs6V2cMcagSPn+NWpD+OEYUYLIf6ecOa48cFGeUg=

2. How I run Caddy:

a. System environment:

Docker

b. Command:

docker run --rm  -v /tmp/Caddyfile:/tmp/Caddyfile caddy caddy adapt --config /tmp/Caddyfile --adapter caddyfile

c. Service/unit/compose file:

None

d. My complete Caddyfile or JSON config:

{
  acme_ca https://127.0.0.1:8444/acme/acme/directory
}

foo.local 

3. The problem I’m having:

Caddy adapt generates:

{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "listen": [
            ":443"
          ],
          "routes": [
            {
              "match": [
                {
                  "host": [
                    "foo.local"
                  ]
                }
              ],
              "terminal": true
            }
          ]
        }
      }
    }
  }
}

While v2.4.3 (or if I use a domain that doesn’t end in .local generates:

{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "listen": [
            ":443"
          ],
          "routes": [
            {
              "match": [
                {
                  "host": [
                    "foo.local"
                  ]
                }
              ],
              "terminal": true
            }
          ]
        }
      }
    },
    "tls": {
      "automation": {
        "policies": [
          {
            "subjects": [
              "foo.local"
            ],
            "issuers": [
              {
                "ca": "https://127.0.0.1:8444/acme/acme/directory",
                "module": "acme"
              }
            ]
          }
        ]
      }
    }
  }
}

On my local machine I configured .local to redirect to localhost, and I have a local step-ca server to generate certs for all my .local domains. The problem after updating to 2.4.5 is that caddy tries to obtain the certificates from let’s enctrypt (instead of using my local ACME server)

Not sure if that change is intentional

4. Error messages and/or full log output:

5. What I already tried:

6. Links to relevant resources:

That would be because of this commit:

Basically, certmagic.SubjectIsInternal("foo.local") is true:

// SubjectIsInternal returns true if subj is an internal-facing
// hostname or address.
func SubjectIsInternal(subj string) bool {
	return subj == "localhost" ||
		strings.HasSuffix(subj, ".localhost") ||
		strings.HasSuffix(subj, ".local")
}

Generally though, it’s not recommended to use .local for home networking this way, because generally that’s used for multicast DNS, so you might have some fighting going on if you have Apple devices in your network using Bonjour.

The better TLD to use for home networking generally is .home.arpa. While it’s ugly, that’s the “right” thing to use.

Or even better, use a domain name you actually own, and use subdomains on that with split-DNS so it resolves to LAN IPs in your home network.

3 Likes

Thanks for such a detailed answer :slight_smile:

1 Like

I hope you don’t mind another “me too” on the advice of avoiding .local as a TLD except for where Apple devices use it for Bonjour. I can tell you from experience that a single Apple device on my network caused truly awful confusion. I wish I could remember exactly what the effects were. I believe the Mac made certain assumptions I didn’t expect from my non-Mac experience, and other machines trying to resolve that TLD seemed to get bogged down with some sort of negotiated confusion with the Mac which I didn’t think should be talking to the Mac at all.

I don’t know your needs, but I have been very very happy using a PiHole for my home network DNS. I use subdomains off of a domain I own anyway so that any mistake still only hits a server I own. Meanwhile, telling my router to use the PiHole for DNS meant no having to manage host files per machine. DNS won’t care if local.yourdomain.com points to 127.0.0.1. :blush:

1 Like