Caddy error on https://127.0.0.1/ or sub1.localhost

1. The problem I’m having:

I want to use Caddy on https://localhost, https://sub1.localhost and https://127.0.0.1 but it won’t establish a TLS connection for anything other than localhost.

2. Error messages and/or full log output:

> curl -i -k "https://localhost/"
HTTP/1.1 200 OK
Alt-Svc: h3=":443"; ma=2592000
Content-Type: text/plain; charset=utf-8
Server: Caddy
Date: Sat, 02 Mar 2024 14:46:19 GMT
Content-Length: 25

Hello, Default! localhost

> curl -i -k "https://sub1.localhost/"
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.

> curl -i -k "https://127.0.0.1/"
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.
caddy-caddy-1  | {"level":"debug","ts":1709393622.499043,"logger":"events","msg":"event","name":"tls_get_certificate","id":"ac0a2843-0ab6-4644-89f3-a703369ef5da","origin":"tls","data":{"client_hello":{"CipherSuites":[49196,49195,49200,49199,159,158,49188,49187,49192,49191,49162,49161,49172,49171,157,156,61,60,53,47,10],"ServerName":"","SupportedCurves":[29,23,24],"SupportedPoints":"AA==","SignatureSchemes":[2052,2053,2054,1025,1281,513,1027,1283,515,514,1537,1539],"SupportedProtos":["http/1.1"],"SupportedVersions":[771,770,769],"RemoteAddr":{"IP":"172.22.0.1","Port":42230,"Zone":""},"LocalAddr":{"IP":"172.22.0.2","Port":443,"Zone":""}}}}
caddy-caddy-1  | {"level":"debug","ts":1709393622.499114,"logger":"tls.handshake","msg":"no matching certificates and no custom selection logic","identifier":"172.22.0.2"}
caddy-caddy-1  | {"level":"debug","ts":1709393622.499124,"logger":"tls.handshake","msg":"no certificate matching TLS ClientHello","remote_ip":"172.22.0.1","remote_port":"42230","server_name":"","remote":"172.22.0.1:42230","identifier":"172.22.0.2","cipher_suites":[49196,49195,49200,49199,159,158,49188,49187,49192,49191,49162,49161,49172,49171,157,156,61,60,53,47,10],"cert_cache_fill":0.0001,"load_or_obtain_if_necessary":true,"on_demand":false}
caddy-caddy-1  | {"level":"debug","ts":1709393622.4992464,"logger":"http.stdlib","msg":"http: TLS handshake error from 172.22.0.1:42230: no certificate available for '172.22.0.2'"}
caddy-caddy-1  | {"level":"debug","ts":1709393624.766157,"logger":"events","msg":"event","name":"tls_get_certificate","id":"09a5e4c7-4b2f-466b-b6c3-692fdd615ad8","origin":"tls","data":{"client_hello":{"CipherSuites":[49196,49195,49200,49199,159,158,49188,49187,49192,49191,49162,49161,49172,49171,157,156,61,60,53,47,10],"ServerName":"sub1.localhost","SupportedCurves":[29,23,24],"SupportedPoints":"AA==","SignatureSchemes":[2052,2053,2054,1025,1281,513,1027,1283,515,514,1537,1539],"SupportedProtos":["http/1.1"],"SupportedVersions":[771,770,769],"RemoteAddr":{"IP":"172.22.0.1","Port":42238,"Zone":""},"LocalAddr":{"IP":"172.22.0.2","Port":443,"Zone":""}}}}
caddy-caddy-1  | {"level":"debug","ts":1709393624.766217,"logger":"tls.handshake","msg":"no matching certificates and no custom selection logic","identifier":"sub1.localhost"}
caddy-caddy-1  | {"level":"debug","ts":1709393624.7662218,"logger":"tls.handshake","msg":"no matching certificates and no custom selection logic","identifier":"*.localhost"}
caddy-caddy-1  | {"level":"debug","ts":1709393624.766224,"logger":"tls.handshake","msg":"no matching certificates and no custom selection logic","identifier":"*.*"}
caddy-caddy-1  | {"level":"debug","ts":1709393624.7662292,"logger":"tls.handshake","msg":"no certificate matching TLS ClientHello","remote_ip":"172.22.0.1","remote_port":"42238","server_name":"sub1.localhost","remote":"172.22.0.1:42238","identifier":"sub1.localhost","cipher_suites":[49196,49195,49200,49199,159,158,49188,49187,49192,49191,49162,49161,49172,49171,157,156,61,60,53,47,10],"cert_cache_fill":0.0001,"load_or_obtain_if_necessary":true,"on_demand":false}
caddy-caddy-1  | {"level":"debug","ts":1709393624.7662942,"logger":"http.stdlib","msg":"http: TLS handshake error from 172.22.0.1:42238: no certificate available for 'sub1.localhost'"}

Note that for 127.0.0.1 the host is not set and caddy assumes 172.22.0.2 was requested?!

3. Caddy version:

v2.7.6 h1:w0NymbG2m9PcvKWsrXO6EEkY9Ru4FJK8uQbYcev1p3A=

4. How I installed and ran Caddy:

a. System environment:

Windows Docker

b. Command:

docker compose up

c. docker-compose.yml:

version: "3.7"

services:
  caddy:
    image: caddy
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro

d. My complete Caddy config:

{
	local_certs
	debug
}

* {
	respond "Hello, Default! {host}"
}

same without local_certs

Okay, so * does not match dots in DNS names, so that kinda explains sub1.localhost.

Now I tried

{
	debug
	local_certs # same result without
}

https://, http:// {
	respond "Hello, Host: {host}"
}

This works for all http:// requests (now without redirect to https) but not a single https:// request. Now even localhost fails.
http: TLS handshake error from 172.22.0.1:60372: no certificate available for 'localhost'

Caddy doesn’t know which domains to get certificates for; so either you need to specify them in your config (i.e. sub1.localhost instead of a wildcard https://), or enable on-demand TLS (but you’ll need a backend that can approve certificates for certain domains).

Well I plan to use on-demand TLS later, but obviously only for real domains.
I already tried it. If the ask endpoint denies for “localhost” then Caddy will also fail. But I just want it to use a local certificate instead of complete failing.

So just put sub1.localhost (or whatever domain you want to test with) in your Caddyfile and it will make and use a cert for that domain.

I don’t want to name the host explicitly, I want a “catch all”.

{
	debug
	on_demand_tls {
		ask https://httpstat.us/200
	}
}

https:// {
	tls internal {
		on_demand
	}
	respond "Hello Secure, Default! {host}"
}

also fails for https://localhost/

{
	debug
}

https:// {
	tls internal
	respond "Hello Secure, Default! {host}"
}

also fails for https://localhost/

I want a “catch all” that proxies all requests to a backend server. It should work with *.localhost in development and *.example.org in production. Actually it should just work with ANY domain (localhost/example.org shouldn’t be hardcoded).
I do have an ask endpoint that can return 200 for production domains if required.

So I guess this is not possible? It’s not possible to tell Caddy to use its internal CA if it doesn’t have or isn’t allowed to request an official certificate for a domain?

We special-case tls internal to not require the ask endpoint when on-demand is enabled, so this will work:

https:// {
	tls internal {
		on_demand
	}
	respond "Hello Secure, Default! {host}"
}

It does… I wonder why it didn’t work for me with the ask https://httpstat.us/200 above, as it is basically the same. But now this also works.

Nevertheless this is not helpful as now I lost the ability to use real certificates in production. The internal ca should be the fallback, not the default.

Well, you just need to define sites for those other public sites.

example.com {
	respond "example"
}

https:// {
	tls internal {
		on_demand
	}
	respond "Hello Secure, Default! {host}"
}

Caddy will manage a certificate for example.com from public issuers, and if it receives TLS handshakes for any other domain, it’ll issue using its internal issuer.

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