I wanted to create a catch-all configuration that would answer to any http:// or https:// call if the URL is not known at that time (i.e. if there was no match before)
But it does not for HTTPS. The Windows version of the error:
$ curl -v https://sjhkjsdks.swtk.eu
* Trying 88.120.31.79:443...
* Connected to sjhkjsdks.swtk.eu (88.120.31.79) port 443
* schannel: disabled automatic use of client certificate
* ALPN: curl offers http/1.1
* schannel: next InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE (0x80090326) - This error usually occurs when a fatal SSL/TLS alert is received (e.g. handshake failed). More detail may be available in the Windows System event log.
* Closing connection
* schannel: shutting down SSL/TLS connection with sjhkjsdks.swtk.eu port 443
curl: (35) schannel: next InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE (0x80090326) - This error usually occurs when a fatal SSL/TLS alert is received (e.g. handshake failed). More detail may be available in the Windows System event log.
If there’s really nothing in the Caddy logs, then the connection isn’t even reaching Caddy. You should enable debug mode in your config to be sure.
I think I will not have a simple solution then because either I have a correct request and it is handled correctly, or I have an incorrect one (= the app does not exist) and I would need to issue an on_demand TLS request which is exactly what must not be done (because of rate limitations).
I’m not sure if I understand your conclusion. Why are you worried about rate limits exactly?
If Caddy doesn’t have a TLS cert for a domain, then it can’t complete the TLS handshake. On-Demand TLS allows Caddy to issue a certificate right away on the first TLS handshake for a domain, if allowed. If not allowed, it will cause the TLS handshake to fail as normal (the behaviour you’re already seeing).
Yes, that’s right. I am going to try to clarify.
I wanted to send back a 410 when there is no match in caddy. This means that if someone sent me 10000 requests to https://req1.swtk.eu, https://req2.swtk.eu, … https://req10000.swtk.eu, Let’s Encrypt would have been queried 10000 times and I would have hit the quota somewhere in the meantime.
This is a danger that is clearly documented and the solution is to have a database that keeps of the names that have been configured. This is fine, but not relevant to my case because I do not know which domain will be requested.
Hope this is better now.
As for the “why” part: I do not care about forged requests but I have monitoring set up for my services (applications behind caddy). I can have two cases of replies (in addition to a correct one):
if an application really fails (crashes, does not respond, …) I will get a 50x reply and this is for me the signal that something is wrong with my app.
if an application that existed has been removed (deleted), it would be the case of the “forged” URL and I would like to respond with the 410. This will be a signal for me that I have to fix the monitoring
This is in reality a nice to have - I am not Google and have, what, 30 services or so. I add or remove one maybe once a month or even less so whatever I get in the monitoring will mean “something needs to be fixed”. It would be just aesthetically pleasing to differentiate the two cases.
Another thing is that I have a generic domain attacked through typical means - notably though the public certificate log, so for known (and at some point registered) FQDNs. I do not expect to be DDoSed with the 10000 forged URLs I mentioned earlier so I could go for it, use on-demand TLS and hope for the best (worst case I will need to wait until the quota is reset)
If all your domains are subdomains like this, and are for domains under your control, you should just get a wildcard certificate using the ACME DNS challenge. That way you have one certificate that covers those infinite amount of subdomains.
If these are actually customer domains, then you should have a registry in your database of those customer domains. You should reject any unknown domains.
But yeah, it’s impossible to respond with any kind of HTTP status when Caddy doesn’t have a TLS cert, because HTTP doesn’t happen if the TLS handshake fails (TLS wraps HTTP, and therefore is handled before HTTP is decrypted/parsed/executed).
To block clients before a TLS handshake, you won’t be able to use HTTP as Francis mentioned. You’ll need to implement some TCP-layer or IP-layer blocking.
This is also the conclusion I had last night when thinking more about this.
My installation is purely a home self-hosting one (though my sanity and family relationship depend on it because when smart lights do not switch on, well this is not good), I can implement whatever I need.
I’ve been using Caddy for so many years and the TLS part is so seamless that I simply forgot about wildcard certs (though they would neatly map with my wildcard DNS, aesthetically speaking).