Default certificate when no matching SNI

1. The problem I’m having:

I’d like to use a default certificate regardless of the request’s SNI.

My servers are behind Cloudflare. When Cloudflare proxies a request it passes through the SNI of the original request to the origin server. Cloudflare will accept a certificate from the origin if it’s for the requested host or for the configured origin host (ie, making a request for service.example.com with a origin server of origin1.example.com will accept a certificate for either service.example.com or origin1.example.com).

I only want to have the origin servers get certificates (via auto https) for their own hostname and always respond with that certificate. The servers host several different domains. Having the servers issue certificates for every domain is possible, but it would be a bit onerous because I’d need to use DNS challenges and to do that in a somewhat secure manner I’d need to delegate the _acme-challenge subdomain for each of them.

As far as I can tell, serving a default certificate, issued via auto https, that doesn’t match the request SNI isn’t supported. Would it be possible to allow this? Alternatively, is it possible for me to write a custom module to get this functionality? I took a brief look at the module documentation but I didn’t immediately see a hook that would allow for this in a clean way.

Thanks!

2. Error messages and/or full log output:

N/A

3. Caddy version:

v2.6.4 h1:2hwYqiRwk1tf3VruhMpLcYTg+11fCdr8S3jhNAdnPy8=

4. How I installed and ran Caddy:

Downloaded Linux amd64 binary from GitHub. Currently running from terminal while testing.

a. System environment:

Debian 11 / amd64

b. Command:

./caddy run --config Caddyfile

d. My complete Caddy config:

I can’t include a non-redacted config, I don’t think it’s particularly relevant for my question but I understand if you’re unable to provide assistance. I may be able to create an example/repro config with different (but real) domains if you deem it necessary. My apologies.

5. Links to relevant resources:

Contains a Common Name (CN) or Subject Alternative Name (SAN) that matches the requested or target hostname.

There is the default_sni global option which can set a default if the client didn’t set SNI at all, but there’s currently nothing to fallback/retry to the default if no cert is found.

I’m not sure that would work anyway, because the clients are expected to verify that the cert they got matches the SNI they requested. If it doesn’t, then they should fail the TLS handshake.

No I don’t think there’s any hooks available in the tls app that would allow this to work.

I’ll have to let @matt comment on this. But my immediate reaction is that it would be gross to allow Caddy to serve a cert that doesn’t match the requested SNI.

1 Like

Thanks for the response!

I’m not sure that would work anyway, because the clients are expected to verify that the cert they got matches the SNI they requested. If it doesn’t, then they should fail the TLS handshake.

In the typical case of a client accessing the server directly, I agree it shouldn’t accept any name other than the one being requested. In this case Cloudflare is terminating the client’s TLS connection and has a valid certificate for the service (service.example.com for example sake). When Cloudflare makes the request to the origin server it can be less strict because while the original request may be for service.example.com Cloudflare is making the origin request to origin1.example.com, so there’s no real issue accepting either of the names.

But my immediate reaction is that it would be gross to allow Caddy to serve a cert that doesn’t match the requested SNI.

It doesn’t when using auto https, but if the cert is statically configured as below, Caddy serves it regardless of SNI. I suppose another way of phrasing my request is to allow the same behavior as a static certificate, but managed by auto https.

:443 {
    tls cert.pem key.pem

    ...
}
1 Like

Does default_sni not work for your use case?

You can probably use a certificate manager module to load a specific certificate at handshake-time.

Just curious, what company are you with that is using Caddy?

Does default_sni not work for your use case?

Unfortunately not. Cloudflare passes through the original SNI from the client’s request (client → Cloudflare) in the backend request (Cloudflare → origin) and default_sni only applies to requests with an empty SNI from what I understand. I did test it, but no luck.

You can probably use a certificate manager module to load a specific certificate at handshake-time.

Would that allow loading certificates that are managed by Caddy? My impression was that a certificate manager module was for retrieving externally managed certificates.

Just curious, what company are you with that is using Caddy?

MyRadar / ACME AtronOmatic. We’re currently using NGINX. I’m evaluating switching to Caddy.

1 Like

@kale Ohh I’m a big fan of weather apps like this.

So here’s my current idea for you: use tls directive to load Caddy’s auto-managed certs, like so (adjust paths to your system):

tls /var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/example.com/example.com.crt /var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/example.com/example.com.key

The only caveat is you’ll need to reload your config once every 90 days.

If we can get your company set up on a sufficient sponsorship tier I can prioritize a feature that I think would be helpful, we can do this one of two ways:

  1. Have Caddy automatically reload certs that change on disk (not my favorite, but doable)
  2. or enable a new config option that forces Caddy to always serve a cert for a specific name even if it doesn’t match.

I think I lean toward 2, although 1 might be easier :man_shrugging: We could discuss as we get to that point.

PS. You might be able to force this already using a JSON config. I’d have to look deeper to verify.

1 Like

I just downloaded this for my Android phone and wow :heart_eyes: Instantly my favorite radar app. I’m currently using RadarOmega and RadarScope but am looking forward to using MyRadar, I’ll have to see if it has the features I need/like :+1:

2 Likes

So here’s my current idea for you: use tls directive to load Caddy’s auto-managed certs

I had considered that as well. I wasn’t sure if it would be “safe” though. I think we’d need to do a bit of a partial startup on initial deployment since Caddy requires the referenced files to exist on start and it needs to start to issue the certs.

I may bite the bullet and try out issuing the individual certificates via DNS challenge rather than trying to use Caddy in a way it’s not designed to be.

If we can get your company set up on a sufficient sponsorship tier I can prioritize a feature that I think would be helpful

I will definitely keep this in mind!

I just downloaded this for my Android phone and wow :heart_eyes: Instantly my favorite radar app. I’m currently using RadarOmega and RadarScope but am looking forward to using MyRadar, I’ll have to see if it has the features I need/like :+1:

Thank you for the kind words! Feel free to DM me if you have any feedback, radar products are one of my areas of responsibility.

1 Like

I really want to know more about your deployment! If you could talk to the right people about a sponsorship / support plan, I could work with your team in private to get it resolved, and prioritize the requisite features – and even just implement them right away.

I’m currently trying to understand how companies use Caddy and to get working relationships with them so we can build a better product that suits their needs in an ideal way. :+1:

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