Using wildcard to match hostnames

With both Apache and Nginx, * matches both and

With Caddy it does not, it only matches

Is there any rationale behind this decision? Or is there a way in Caddy to accomplish the same result? Adding *.*, *.*.* and so on becomes just ridiculous.

Caddy is following this RFC:

Also, the concept of wildcard labels was in an RFC from as early as 1987:

Do you really need this though? Why would you ever need more than 2 or 3 levels?


Caddy is following this RFC:
RFC 6125 - Representation and Verification of Domain-Based Application Service Identity within Internet Public Key Infrastructure Using X.509 (PKIX) Certificates in the Context of Transport Layer Security (TLS)

That’s for certificates, not general domain-names.

Also, the concept of wildcard labels was in an RFC from as early as 1987:
RFC 1034 - Domain names - concepts and facilities

1034 was updated in 4592:

*.example. 3600 TXT "this is a wildcard" QTYPE=TXT, QCLASS=IN
          the answer will be " IN TXT ..."
          because bar.example. does not exist, but the wildcard

Caddy’s domain rules need to follow from certificate rules, because it does the extra job of managing certificates automatically. Other web servers don’t do that.

1 Like

So creating a definition like the one below and have it respond to shouldn’t be a problem?

http://* {
    file_server /tmp

Also… since you allow for *.* which isn’t allowed as per 6125, you’re already not really following the RFC…

You can do it with a header_regexp matcher.

http:// {
	@allSubdomains header_regexp sub Host (.*)\
	handle @allSubdomains {
		respond "Handling {re.sub.1}" 200

	handle {
		# Fallback for anything not otherwise matched

Won’t that example break http->https redirection?

It looks like it catches all http-traffic and then uses header_regexp to do the logic?

Yes it will. So pick your poison. If you still need HTTP->HTTPS redirects alongside this, then you need to do it yourself for the domains you still need redirects for. It’s really just redir https://<domain>{uri} 308, and fill in <domain> however you need. You could use map (Caddyfile directive) — Caddy Documentation to match the domains you need.

1 Like

Okay…just trying to figure out things here… This is a heck of a lot more complicated than how it’s done in Nginx or Apache :slight_smile:

I still don’t see why *, or something else, like maybe ** can’t match

RFC6125 can’t really be the reason, since you support *.*, which 6125 explicitly forbids…

And you even have a on-demand feature for getting certificates, so allow * to match whatever, then you combine it with on_demand and everything should work fine?

Where, exactly?

  1. The client SHOULD NOT attempt to match a presented identifier in
    which the wildcard character comprises a label other than the
    left-most label (e.g., do not match bar.*
  2. If the wildcard character is the only character of the left-most
    label in the presented identifier, the client SHOULD NOT compare
    against anything but the left-most label of the reference
    identifier (e.g., * would match but
    not or

Ah, well:

This is about the client, not the server; and a “SHOULD NOT” phrase is weaker than a “MUST NOT” – you’ll find that most major web browsers do accept certificates like *.* (but not *.* – individual implementations are nuanced like that). Also, in *.*, the wildcard does comprise the left-most label, so there is an argument this does not apply anyway (see example).

While I believe publicly-trusted CAs are generally forbidden from issuing wildcard certificates with multiple wildcard labels by the BRs, this does not prevent servers from serving certificates with such subjects; and this is often in fact useful.

Is irrelevant, again, as it describes what the client “SHOULD NOT” do (i.e. is a recommendation), not saying what is forbidden by servers or X.509 Certificate issuers. See the example – it’s saying that the wildcard in a label does not apply to incongruent labels when comparing the identifier, i.e. the domains must have the same number of labels.

1 Like

I still think it’s a really weird stance to take.

Apache and Nginx both follows RFC4592, Caddy does not.

And I see no reason why Caddy doesn’t. You even have a fancy on-demand feature that would take care of all the certificate-problems.

Set up *, create a letsencrypt for *, and if some option is set, create one on the fly when is accessed.

You probably want to use a catch-all site address like :443, then, rather than enumerating all possible subdomains, when using on-demand TLS.

There’s a lot of things Caddy does differently than other servers. :slight_smile: That’s the whole point. Francis already explained why this one is.

There’s a lot of things Caddy does differently than other servers. :slight_smile: That’s the whole point. Francis already explained why this one is.

Not really… since you can set up on-demand certs there is zero reason for it.

If it’s just a matter of not wanting to support it, fine, but referring to RFCs doesn’t really work, since we have established that Caddy doesn’t follow 4562 already.
And the issue with certificates is easily taken care of with on demand certs, which would keep Caddy compliant with 6125

I’m not sure we have. What about this part, which follows on immediately after the area you quoted?

The final example highlights one common misconception about
wildcards. A wildcard “blocks itself” in the sense that a wildcard
does not match its own subdomains. That is, “*.example.” does not
match all names in the “example.” zone; it fails to match the names
below “*.example.”. To cover names under “*.example.”, another
wildcard domain name is needed–"*.*.example."–which covers all but
its own subdomains.

—RFC 4592 - The Role of Wildcards in the Domain Name System


I’m not sure what you mean… That text refers to

QNAME=ghost.*.example., QTYPE=MX, QCLASS=IN
because *.example. exists

And since there is the line

*.example. 3600 MX 10 host1.example.

It matches on that

If you look at the list of examples, you’ll find that the second set of examples (including that last example) are

responses [that] would not be synthesized from any of the wildcards in the zone

(emphasis mine), whereas the example you cited above is from the list of responses that would be synthesized from one of the wildcards.

The wording itself seems quite explicit and very much seems to be against your point; I’m not sure how the two can be reconciled.

1 Like