Docker with `tls internal` only allows a single IP address (default container IP), all other IP addresses considered insecure certificates

1. Caddy version (caddy version):

2.2.0-rc.1

2. How I run Caddy:

a. System environment:

Linux - Manjaro KDE
Docker 19.03

b. Command:

docker run --rm -it \
--name caddytest \
-p 80:80 -p 443:443 \
-v $PWD/public:/usr/share/caddy/ \
-v $PWD/caddy/data:/data  \
-v $PWD/caddy/Caddyfile:/etc/caddy/Caddyfile

c. Service/unit/compose file:

N/A

d. My complete Caddyfile or JSON config:

192.168.1.42, 127.0.0.1, 0.0.0.0, 172.17.0.23 localhost {
  tls internal
  root * /usr/share/caddy
  file_server
}

3. The problem I’m having:

With docker, when using IP addresses to access the Caddy container, HTTPS with tls internal will fail to be considered secure unless using the containers assigned IP address. Any other IP that connects to that container sets the Subject Alternative Name as the containers IP.

I can set the global Caddyfile option default_sni to a different IP address (the container IP address must be removed from the site block site addresses for that to work), and now that IP address is presented in the Subject Alternative Name for the TLS cert, however, the other IP addresses will fail for the same original reason, just a different IP for SAN. The default_sni value must be in the list of site addresses, otherwise it still attempts to use the container IP for establishing the connection (which fails, since you’ve removed it for the site block).

When running the container with --network host, each IP address resolves with a TLS cert that has that same IP in the SAN.

{
  default_sni 192.168.1.42
}

192.168.1.42, 127.0.0.1, 0.0.0.0, localhost {
  tls internal
  root * /usr/share/caddy
  file_server
}

I don’t need to access the container via the container IP, and for my needs accessing via the single LAN IP is fine. I’m just not sure why Caddy is behaving differently with SAN when changing the container from the Docker network to the host network.

4. Error messages and/or full log output:

Accessing 192.168.1.8: NET::ERR_CERT_COMMON_NAME_INVALID (Chrome error page)
Accessing 172.17.0.23: Works fine, TLS cert trusted.

2020/09/11 06:23:18.608 INFO    using provided configuration    {"config_file": "/etc/caddy/Caddyfile", "config_adapter": "caddyfile"}
2020/09/11 06:23:18.609 INFO    admin   admin endpoint started  {"address": "tcp/localhost:2019", "enforce_origin": false, "origins": ["localhost:2019", "[::1]:2019", "127.0.0.1:2019"]}
2020/09/11 06:23:18.609 INFO    tls.cache.maintenance   started background certificate maintenance      {"cache": "0xc0004b8540"}
2020/09/11 06:23:18.617 INFO    http    server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2020/09/11 06:23:18.617 INFO    http    enabling automatic HTTP->HTTPS redirects        {"server_name": "srv0"}
2020/09/11 06:23:18.651 WARN    pki.ca.local    installing root certificate (you might be prompted for password)        {"path": "storage:pki/authorities/local/root.crt"}
2020/09/11 06:23:18 Warning: "certutil" is not available, install "certutil" with "apt install libnss3-tools" or "yum install nss-tools" and try again
2020/09/11 06:23:18 define JAVA_HOME environment variable to use the Java trust
2020/09/11 06:23:18 certificate installed properly in linux trusts
2020/09/11 06:23:18.677 INFO    http    enabling automatic TLS certificate management   {"domains": ["127.0.0.1", "0.0.0.0", "172.17.0.23", "localhost", "192.168.1.42"]}
2020/09/11 06:23:18.678 WARN    tls     stapling OCSP   {"error": "no OCSP stapling for [127.0.0.1]: no OCSP server specified in certificate"}
2020/09/11 06:23:18.678 WARN    tls     stapling OCSP   {"error": "no OCSP stapling for [0.0.0.0]: no OCSP server specified in certificate"}
2020/09/11 06:23:18.678 INFO    tls     cleaned up storage units
2020/09/11 06:23:18.678 WARN    tls     stapling OCSP   {"error": "no OCSP stapling for [172.17.0.23]: no OCSP server specified in certificate"}
2020/09/11 06:23:18.679 WARN    tls     stapling OCSP   {"error": "no OCSP stapling for [localhost]: no OCSP server specified in certificate"}
2020/09/11 06:23:18.679 WARN    tls     stapling OCSP   {"error": "no OCSP stapling for [192.168.1.42]: no OCSP server specified in certificate"}
2020/09/11 06:23:18.679 INFO    autosaved config        {"file": "/config/caddy/autosave.json"}
2020/09/11 06:23:18.679 INFO    serving initial configuration
2020/09/11 06:23:33 http: TLS handshake error from 192.168.1.42:45506: remote error: tls: unknown certificate

5. What I already tried:

Updated Caddy to 2.2.0-rc.1 release which includes a related fix for hostnames. Hostnames work fine in Chrome now, the IP SAN mismatch issue described here is considered insecure by both Firefox and Chrome.

Searched forum and found this thread for the tip on default_sni.

Tried --network host, which works without adjusting default_sni, unclear why the behavior is different when using the Docker network.

Provided my own certificate generated from mkcert with SAN including all site addresses for the block, works well, including when using the host network to access from another device on the LAN.

You could try on-demand internal certificates maybe:

tls internal {
	on_demand
}

You could just change the site address to https:// and let Caddy make certs for whatever hostname is requested, on the fly. I think that might do the trick.

What are the requests that are failing? (show curl -v please)

Hope the following is helpful, most of the logs are the same for fail/success output, only 0.0.0.0 is resolving (2nd line curl output for “Connected”) to 127.0.0.1, and localhost which I’ve omitted but works without issue is resolving to ::1.


Docker command (caddy_tmp is locally built 2.2.0-RC.1 image, modified official alpine Dockerfile):

docker run --rm -it \
--name caddytest \
-p 80:80 -p 443:443 \
-v $PWD/public:/usr/share/caddy/ \
-v $PWD/caddy/data:/data  \
-v $PWD/caddy/Caddyfile:/etc/caddy/Caddyfile \
caddy_tmp

Caddyfile:

192.168.1.42, 127.0.0.1, 0.0.0.0, 172.17.0.23, localhost {
  respond "Hello"
}

172.17.0.23 (success)
$ curl -v https://172.17.0.23
*   Trying 172.17.0.23:443...
* Connected to 172.17.0.23 (172.17.0.23) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 03:13:18 2020 GMT
*  expire date: Sep 12 15:14:18 2020 GMT
*  subjectAltName: host "172.17.0.23" matched cert's IP address!
*  issuer: CN=Caddy Local Authority - ECC Intermediate
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x560f070089f0)
> GET / HTTP/2
> Host: 172.17.0.23
> user-agent: curl/7.71.1
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200 
< server: Caddy
< content-length: 5
< date: Sat, 12 Sep 2020 03:14:51 GMT
< 
* Connection #0 to host 172.17.0.23 left intact
Hello
192.168.1.42 (fail)
$ curl -v https://192.168.1.42
*   Trying 192.168.1.42:443...
* Connected to 192.168.1.42 (192.168.1.8) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 03:13:18 2020 GMT
*  expire date: Sep 12 15:14:18 2020 GMT
*  subjectAltName does not match 192.168.1.42
* SSL: no alternative certificate subject name matches target host name '192.168.1.42'
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
curl: (60) SSL: no alternative certificate subject name matches target host name '192.168.1.42'
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above

With --network host to use host network (that 192.168.1.42 points to from any other device on LAN):

192.168.1.42 (success)
$ curl -v https://192.168.1.42
*   Trying 192.168.1.42:443...
* Connected to 192.168.1.42 (192.168.1.42) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 03:13:18 2020 GMT
*  expire date: Sep 12 15:14:18 2020 GMT
*  subjectAltName: host "192.168.1.42" matched cert's IP address!
*  issuer: CN=Caddy Local Authority - ECC Intermediate
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x561b9ef929f0)
> GET / HTTP/2
> Host: 192.168.1.42
> user-agent: curl/7.71.1
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200 
< server: Caddy
< content-length: 5
< date: Sat, 12 Sep 2020 03:22:25 GMT
< 
* Connection #0 to host 192.168.1.42 left intact
Hello

Same output success for default_sni on the Docker network (172.17.0.23, removed from site block for default_sni to work):

{
  default_sni 192.168.1.42
}

192.168.1.42, 127.0.0.1, 0.0.0.0, localhost {
  respond "Hello"
}
0.0.0.0 (fail)
$ curl -v https://0.0.0.0
*   Trying 0.0.0.0:443...
* Connected to 0.0.0.0 (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 03:13:18 2020 GMT
*  expire date: Sep 12 15:14:18 2020 GMT
*  subjectAltName does not match 0.0.0.0
* SSL: no alternative certificate subject name matches target host name '0.0.0.0'
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
curl: (60) SSL: no alternative certificate subject name matches target host name '0.0.0.0'
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
127.0.0.1 (fail)
$ curl -v https://127.0.0.1
*   Trying 127.0.0.1:443...
* Connected to 127.0.0.1 (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 03:13:18 2020 GMT
*  expire date: Sep 12 15:14:18 2020 GMT
*  subjectAltName does not match 127.0.0.1
* SSL: no alternative certificate subject name matches target host name '127.0.0.1'
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
curl: (60) SSL: no alternative certificate subject name matches target host name '127.0.0.1'
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

With default_sni 0.0.0.0:

0.0.0.0 (success)
$ curl -v https://0.0.0.0
*   Trying 0.0.0.0:443...
* Connected to 0.0.0.0 (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 02:53:58 2020 GMT
*  expire date: Sep 12 14:54:58 2020 GMT
*  subjectAltName: host "0.0.0.0" matched cert's IP address!
*  issuer: CN=Caddy Local Authority - ECC Intermediate
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55cadfd2d9f0)
> GET / HTTP/2
> Host: 0.0.0.0
> user-agent: curl/7.71.1
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200 
< server: Caddy
< content-length: 5
< date: Sat, 12 Sep 2020 03:48:14 GMT
< 
* Connection #0 to host 0.0.0.0 left intact
Hello
127.0.0.1 (fail)
$ curl -v https://127.0.0.1
*   Trying 127.0.0.1:443...
* Connected to 127.0.0.1 (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 04:41:32 2020 GMT
*  expire date: Sep 12 16:42:32 2020 GMT
*  subjectAltName does not match 127.0.0.1
* SSL: no alternative certificate subject name matches target host name '127.0.0.1'
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
curl: (60) SSL: no alternative certificate subject name matches target host name '127.0.0.1'
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

With default_sni 127.0.0.1:

0.0.0.0 (fail)
$ curl -v https://0.0.0.0
*   Trying 0.0.0.0:443...
* Connected to 0.0.0.0 (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 04:41:32 2020 GMT
*  expire date: Sep 12 16:42:32 2020 GMT
*  subjectAltName does not match 0.0.0.0
* SSL: no alternative certificate subject name matches target host name '0.0.0.0'
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
curl: (60) SSL: no alternative certificate subject name matches target host name '0.0.0.0'
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
127.0.0.1 (success)
$ curl -v https://127.0.0.1
*   Trying 127.0.0.1:443...
* Connected to 127.0.0.1 (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 04:41:32 2020 GMT
*  expire date: Sep 12 16:42:32 2020 GMT
*  subjectAltName: host "127.0.0.1" matched cert's IP address!
*  issuer: CN=Caddy Local Authority - ECC Intermediate
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x560b259c19f0)
> GET / HTTP/2
> Host: 127.0.0.1
> user-agent: curl/7.71.1
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200 
< server: Caddy
< content-length: 5
< date: Sat, 12 Sep 2020 04:44:17 GMT
< 
* Connection #0 to host 127.0.0.1 left intact
Hello

With --network host and default_sni 192.168.1.42 (default_sni has no effect on 127.0.0.1):

127.0.0.1 (success)
$ curl -v https://127.0.0.1
*   Trying 127.0.0.1:443...
* Connected to 127.0.0.1 (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 02:53:58 2020 GMT
*  expire date: Sep 12 14:54:58 2020 GMT
*  subjectAltName: host "127.0.0.1" matched cert's IP address!
*  issuer: CN=Caddy Local Authority - ECC Intermediate
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x5591d8ed09f0)
> GET / HTTP/2
> Host: 127.0.0.1
> user-agent: curl/7.71.1
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200 
< server: Caddy
< content-length: 5
< date: Sat, 12 Sep 2020 03:39:07 GMT
< 
* Connection #0 to host 127.0.0.1 left intact
Hello

Fails with --network host, with or without default_sni 0.0.0.0:

0.0.0.0 (fail)
$ curl -v https://0.0.0.0
*   Trying 0.0.0.0:443...
* Connected to 0.0.0.0 (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 02:53:58 2020 GMT
*  expire date: Sep 12 14:54:58 2020 GMT
*  subjectAltName does not match 0.0.0.0
* SSL: no alternative certificate subject name matches target host name '0.0.0.0'
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
curl: (60) SSL: no alternative certificate subject name matches target host name '0.0.0.0'
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

EDIT:

Removing 127.0.0.1, similar to the removal of 172.17.0.23 on the Docker network, allows for default_sni 0.0.0.0 to have success with --network host:

{
  default_sni 0.0.0.0
}

192.168.1.42, 0.0.0.0, localhost {
  respond "Hello"
}
0.0.0.0
$ curl -v https://0.0.0.0
*   Trying 0.0.0.0:443...
* Connected to 0.0.0.0 (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 12 02:53:58 2020 GMT
*  expire date: Sep 12 14:54:58 2020 GMT
*  subjectAltName: host "0.0.0.0" matched cert's IP address!
*  issuer: CN=Caddy Local Authority - ECC Intermediate
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55c1f55799f0)
> GET / HTTP/2
> Host: 0.0.0.0
> user-agent: curl/7.71.1
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200 
< server: Caddy
< content-length: 5
< date: Sat, 12 Sep 2020 04:17:05 GMT
< 
* Connection #0 to host 0.0.0.0 left intact
Hello

This is successful regardless of --network host. However, if removing the default_sni, the config produces a different error:

0.0.0.0 (fail - internal error)
curl -v https://0.0.0.0
*   Trying 0.0.0.0:443...
* Connected to 0.0.0.0 (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS alert, internal error (592):
* error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
* Closing connection 0
curl: (35) error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error

Which is understandable, since 0.0.0.0 isn’t really a specific IP/interface?

1 Like

All with --network host as a narrow test case,

Only 127.0.0.1 connects to HTTPS:

0.0.0.0, 127.0.0.1 {
  respond "Hello"
}

or

127.0.0.1 {
  respond "Hello"
}

Doesn’t work for 0.0.0.0 or 127.0.0.1, internal error (only for handling TLS, provides “Hello” response over HTTP if redirect is avoided):

0.0.0.0 {
  respond "Hello"
}

Can connect to 0.0.0.0 with HTTPS successfully, 127.0.0.1 fails:

{
  default_sni 0.0.0.0
}

0.0.0.0 {
  respond "Hello"
}

default_sni ignored, 127.0.0.1 takes precedence and connects to HTTPS, 0.0.0.0 fails:

{
  default_sni 0.0.0.0
}

0.0.0.0, 127.0.0.1 {
  respond "Hello"
}

Both successful:

{
  default_sni 0.0.0.0
}

0.0.0.0, 192.168.1.42 {
  respond "Hello"
}

192.168.1.42 successful, 0.0.0.0 internal error.

0.0.0.0, 192.168.1.42 {
  respond "Hello"
}

192.168.1.42 fail, 0.0.0.0 success.
192.168.1.42 forced redirect HTTP->HTTPS.

{
  default_sni 0.0.0.0
}

http://0.0.0.0, https://0.0.0.0 {
  respond "Hello"
}

192.168.1.42 fail, 0.0.0.0 internal error.
192.168.1.42 HTTP returns blank page (empty response body), same for any other address that resolves to the port/system but not assigned a site block (localhost, 127.0.0.1). Although afaik that’s intentional and has nothing to do with 0.0.0.0 as a site address, but due to 0.0.0.0 as default bind directive for interface to listen to?

{
  auto_https disable_redirects
}

http://0.0.0.0, https://0.0.0.0 {
  respond "Hello"
}

For HTTP can wildcard with :80 / http://, but HTTPS doesn’t seem possible with :443 (Connection refused), or *:443 / https:// (Internal error).

1 Like

Thanks, that’s very helpful.

I suppose if I had known you were going to run a whole suite of experiments I would have suggested a more thorough command:

echo | openssl s_client -showcerts -servername SNI -connect HOST:443 2>/dev/null | openssl x509 -text

This will provide the details of the certificate being served including its SAN extension, which is important to this problem. Replace SNI and HOST with their respective values (or omit the -servername argument altogether).

Also, note that IP addresses are not used in the ServerName extension, at least by browsers, as that’s not part of the spec. So using -servername 127.0.0.1 for example will not yield a realistic experiment.

1 Like

Docker command (~same as earlier~ EDIT: Accidentally did all test results below with 2.1.1):

docker run --rm -it \
--name caddytest \
-p 80:80 -p 443:443 \
-v $PWD/public:/usr/share/caddy/ \
-v $PWD/caddy/data:/data  \
-v $PWD/caddy/Caddyfile:/etc/caddy/Caddyfile \
caddy

Caddyfile:

192.168.1.8, 127.0.0.1, 0.0.0.0, 172.17.0.2 {
  respond "Hello"
}

openssl output:

192.168.1.8 (success)
$ echo | openssl s_client -showcerts -servername 192.168.1.8 -connect 192.168.1.8:443 2>/dev/null | openssl x509 -te
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            18:3b:ce:f9:77:c7:6d:2c:be:c7:fa:03:68:ba:c8:53
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = Caddy Local Authority - ECC Intermediate
        Validity
            Not Before: Sep 13 00:34:13 2020 GMT
            Not After : Sep 13 12:35:13 2020 GMT
        Subject: 
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:7a:25:da:f2:03:4f:2b:c9:54:da:3c:95:bb:39:
                    29:4b:0e:63:aa:d4:45:30:8f:e6:cf:22:f3:b7:28:
                    a6:5f:a5:cb:db:72:09:a8:f1:41:a5:7b:33:78:75:
                    51:a1:9c:9f:85:6d:40:69:34:6d:cf:7e:ff:9f:ba:
                    59:0c:34:d9:08
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Key Identifier: 
                37:27:EB:14:E3:4F:F2:59:90:57:3E:C5:5A:64:BE:C7:73:AA:ED:BA
            X509v3 Authority Key Identifier: 
                keyid:8B:BE:D9:7C:3E:32:B2:A9:24:D8:38:42:5F:7B:89:DE:CA:87:58:88

            X509v3 Subject Alternative Name: 
                IP Address:192.168.1.8
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:21:00:de:33:a0:5c:ab:9b:ea:bc:cb:03:6a:4c:0c:
         83:db:32:eb:1a:20:73:41:6e:75:95:38:10:23:6c:2c:d5:da:
         94:02:20:6b:37:8e:f6:c5:1e:5f:8c:0e:83:1e:0f:90:d7:cd:
         04:2e:d4:db:20:05:e5:93:04:fc:ed:83:38:67:f3:ca:29
-----BEGIN CERTIFICATE-----
MIIBtTCCAVugAwIBAgIQGDvO+XfHbSy+x/oDaLrIUzAKBggqhkjOPQQDAjAzMTEw
LwYDVQQDEyhDYWRkeSBMb2NhbCBBdXRob3JpdHkgLSBFQ0MgSW50ZXJtZWRpYXRl
MB4XDTIwMDkxMzAwMzQxM1oXDTIwMDkxMzEyMzUxM1owADBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABHol2vIDTyvJVNo8lbs5KUsOY6rURTCP5s8i87copl+ly9ty
CajxQaV7M3h1UaGcn4VtQGk0bc9+/5+6WQw02QijgYMwgYAwDgYDVR0PAQH/BAQD
AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUNyfr
FONP8lmQVz7FWmS+x3Oq7bowHwYDVR0jBBgwFoAUi77ZfD4ysqkk2DhCX3uJ3sqH
WIgwDwYDVR0RBAgwBocEwKgBCDAKBggqhkjOPQQDAgNIADBFAiEA3jOgXKub6rzL
A2pMDIPbMusaIHNBbnWVOBAjbCzV2pQCIGs3jvbFHl+MDoMeD5DXzQQu1NsgBeWT
BPztgzhn88op
-----END CERTIFICATE-----

No -servername 192.168.1.8:

192.168.1.8 (mismatch with SAN)
echo | openssl s_client -showcerts -connect 192.168.1.8:443 2>/dev/null | openssl x509 -text                        
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            5d:b4:4b:02:42:61:dd:89:98:29:14:fb:60:c0:03:2b
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = Caddy Local Authority - ECC Intermediate
        Validity
            Not Before: Sep 13 00:34:13 2020 GMT
            Not After : Sep 13 12:35:13 2020 GMT
        Subject: 
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:b7:8a:bc:bb:95:73:cd:56:00:37:81:5f:c4:3a:
                    d4:85:59:56:45:3e:c4:35:d0:49:30:c1:eb:8c:94:
                    85:91:fd:b6:cf:af:fd:a8:5d:21:db:ea:f8:a5:4f:
                    f8:87:aa:2a:be:83:06:1d:2f:d5:1f:76:49:38:bf:
                    70:26:f3:19:2c
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Key Identifier: 
                B8:4A:68:3C:58:BD:BB:9B:60:5A:B0:A2:CE:5F:9C:0A:DC:E4:30:FB
            X509v3 Authority Key Identifier: 
                keyid:8B:BE:D9:7C:3E:32:B2:A9:24:D8:38:42:5F:7B:89:DE:CA:87:58:88

            X509v3 Subject Alternative Name: 
                IP Address:172.17.0.2
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:20:58:88:3b:9e:1d:b0:91:ec:5b:7e:9d:38:41:d3:
         f2:4f:dc:bf:85:75:df:0d:6c:e0:7b:2b:36:69:18:44:e0:f0:
         02:21:00:d7:47:22:ec:c1:51:60:df:0f:e9:25:b9:42:89:38:
         1f:bc:94:fa:13:12:29:08:3e:56:52:9d:a4:20:53:bc:37
-----BEGIN CERTIFICATE-----
MIIBtTCCAVugAwIBAgIQXbRLAkJh3YmYKRT7YMADKzAKBggqhkjOPQQDAjAzMTEw
LwYDVQQDEyhDYWRkeSBMb2NhbCBBdXRob3JpdHkgLSBFQ0MgSW50ZXJtZWRpYXRl
MB4XDTIwMDkxMzAwMzQxM1oXDTIwMDkxMzEyMzUxM1owADBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABLeKvLuVc81WADeBX8Q61IVZVkU+xDXQSTDB64yUhZH9ts+v
/ahdIdvq+KVP+IeqKr6DBh0v1R92STi/cCbzGSyjgYMwgYAwDgYDVR0PAQH/BAQD
AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUuEpo
PFi9u5tgWrCizl+cCtzkMPswHwYDVR0jBBgwFoAUi77ZfD4ysqkk2DhCX3uJ3sqH
WIgwDwYDVR0RBAgwBocErBEAAjAKBggqhkjOPQQDAgNIADBFAiBYiDueHbCR7Ft+
nThB0/JP3L+Fdd8NbOB7KzZpGETg8AIhANdHIuzBUWDfD+kluUKJOB+8lPoTEikI
PlZSnaQgU7w3
-----END CERTIFICATE-----

curl output:

192.168.1.8 (fail - mismatch)
curl -v https://192.168.1.8
*   Trying 192.168.1.8:443...
* Connected to 192.168.1.8 (192.168.1.8) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 13 00:34:13 2020 GMT
*  expire date: Sep 13 12:35:13 2020 GMT
*  subjectAltName does not match 192.168.1.8
* SSL: no alternative certificate subject name matches target host name '192.168.1.8'
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
curl: (60) SSL: no alternative certificate subject name matches target host name '192.168.1.8'
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

Caddyfile:

192.168.1.8, 127.0.0.1, 0.0.0.0 {
  respond "Hello"
}
192.168.1.8 (success)
$ echo | openssl s_client -showcerts -servername 192.168.1.8 -connect 192.168.1.8:443 2>/dev/null | openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            18:3b:ce:f9:77:c7:6d:2c:be:c7:fa:03:68:ba:c8:53
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = Caddy Local Authority - ECC Intermediate
        Validity
            Not Before: Sep 13 00:34:13 2020 GMT
            Not After : Sep 13 12:35:13 2020 GMT
        Subject: 
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:7a:25:da:f2:03:4f:2b:c9:54:da:3c:95:bb:39:
                    29:4b:0e:63:aa:d4:45:30:8f:e6:cf:22:f3:b7:28:
                    a6:5f:a5:cb:db:72:09:a8:f1:41:a5:7b:33:78:75:
                    51:a1:9c:9f:85:6d:40:69:34:6d:cf:7e:ff:9f:ba:
                    59:0c:34:d9:08
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Key Identifier: 
                37:27:EB:14:E3:4F:F2:59:90:57:3E:C5:5A:64:BE:C7:73:AA:ED:BA
            X509v3 Authority Key Identifier: 
                keyid:8B:BE:D9:7C:3E:32:B2:A9:24:D8:38:42:5F:7B:89:DE:CA:87:58:88

            X509v3 Subject Alternative Name: 
                IP Address:192.168.1.8
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:21:00:de:33:a0:5c:ab:9b:ea:bc:cb:03:6a:4c:0c:
         83:db:32:eb:1a:20:73:41:6e:75:95:38:10:23:6c:2c:d5:da:
         94:02:20:6b:37:8e:f6:c5:1e:5f:8c:0e:83:1e:0f:90:d7:cd:
         04:2e:d4:db:20:05:e5:93:04:fc:ed:83:38:67:f3:ca:29
-----BEGIN CERTIFICATE-----
MIIBtTCCAVugAwIBAgIQGDvO+XfHbSy+x/oDaLrIUzAKBggqhkjOPQQDAjAzMTEw
LwYDVQQDEyhDYWRkeSBMb2NhbCBBdXRob3JpdHkgLSBFQ0MgSW50ZXJtZWRpYXRl
MB4XDTIwMDkxMzAwMzQxM1oXDTIwMDkxMzEyMzUxM1owADBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABHol2vIDTyvJVNo8lbs5KUsOY6rURTCP5s8i87copl+ly9ty
CajxQaV7M3h1UaGcn4VtQGk0bc9+/5+6WQw02QijgYMwgYAwDgYDVR0PAQH/BAQD
AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUNyfr
FONP8lmQVz7FWmS+x3Oq7bowHwYDVR0jBBgwFoAUi77ZfD4ysqkk2DhCX3uJ3sqH
WIgwDwYDVR0RBAgwBocEwKgBCDAKBggqhkjOPQQDAgNIADBFAiEA3jOgXKub6rzL
A2pMDIPbMusaIHNBbnWVOBAjbCzV2pQCIGs3jvbFHl+MDoMeD5DXzQQu1NsgBeWT
BPztgzhn88op
-----END CERTIFICATE-----

No SNI:

192.168.1.8 (fail - unable to load cert)
$ echo | openssl s_client -showcerts -connect 192.168.1.8:443 2>/dev/null | openssl x509 -text
unable to load certificate
140262127514944:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE

curl:

192.168.1.8 (fail - internal error)
$ curl -v https://192.168.1.8
*   Trying 192.168.1.8:443...
* Connected to 192.168.1.8 (192.168.1.8) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS alert, internal error (592):
* error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
* Closing connection 0
curl: (35) error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error

Same results above with Caddyfile:

192.168.1.8 {
  respond "Hello"
}

I guess that makes sense, since default_sni is a global option, it’s still the IP that will be used in the SAN even when it’s not used with a site block?

As 172.17.0.2 (Docker container IP) is not assigned to a site block, no TLS cert is generated for it? But one for 192.168.1.8 is, so when given an SNI, it finds a certificate to load/respond with?

It’s a bit odd since I can still do a HTTP request and get a response for the IP, but HTTPS fails due to lack of SNI? How did the default_sni setting come about? When is it relevant vs matching the requested site address as fallback? Especially if the default doesn’t have any certificate causing an error?


{
  default_sni 192.168.1.8
}

192.168.1.8 {
  respond "Hello"
}
192.168.1.8 (success)
$ echo | openssl s_client -showcerts -servername 192.168.1.8 -connect 192.168.1.8:443 2>/dev/null | openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            18:3b:ce:f9:77:c7:6d:2c:be:c7:fa:03:68:ba:c8:53
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = Caddy Local Authority - ECC Intermediate
        Validity
            Not Before: Sep 13 00:34:13 2020 GMT
            Not After : Sep 13 12:35:13 2020 GMT
        Subject: 
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:7a:25:da:f2:03:4f:2b:c9:54:da:3c:95:bb:39:
                    29:4b:0e:63:aa:d4:45:30:8f:e6:cf:22:f3:b7:28:
                    a6:5f:a5:cb:db:72:09:a8:f1:41:a5:7b:33:78:75:
                    51:a1:9c:9f:85:6d:40:69:34:6d:cf:7e:ff:9f:ba:
                    59:0c:34:d9:08
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Key Identifier: 
                37:27:EB:14:E3:4F:F2:59:90:57:3E:C5:5A:64:BE:C7:73:AA:ED:BA
            X509v3 Authority Key Identifier: 
                keyid:8B:BE:D9:7C:3E:32:B2:A9:24:D8:38:42:5F:7B:89:DE:CA:87:58:88

            X509v3 Subject Alternative Name: 
                IP Address:192.168.1.8
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:21:00:de:33:a0:5c:ab:9b:ea:bc:cb:03:6a:4c:0c:
         83:db:32:eb:1a:20:73:41:6e:75:95:38:10:23:6c:2c:d5:da:
         94:02:20:6b:37:8e:f6:c5:1e:5f:8c:0e:83:1e:0f:90:d7:cd:
         04:2e:d4:db:20:05:e5:93:04:fc:ed:83:38:67:f3:ca:29
-----BEGIN CERTIFICATE-----
MIIBtTCCAVugAwIBAgIQGDvO+XfHbSy+x/oDaLrIUzAKBggqhkjOPQQDAjAzMTEw
LwYDVQQDEyhDYWRkeSBMb2NhbCBBdXRob3JpdHkgLSBFQ0MgSW50ZXJtZWRpYXRl
MB4XDTIwMDkxMzAwMzQxM1oXDTIwMDkxMzEyMzUxM1owADBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABHol2vIDTyvJVNo8lbs5KUsOY6rURTCP5s8i87copl+ly9ty
CajxQaV7M3h1UaGcn4VtQGk0bc9+/5+6WQw02QijgYMwgYAwDgYDVR0PAQH/BAQD
AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUNyfr
FONP8lmQVz7FWmS+x3Oq7bowHwYDVR0jBBgwFoAUi77ZfD4ysqkk2DhCX3uJ3sqH
WIgwDwYDVR0RBAgwBocEwKgBCDAKBggqhkjOPQQDAgNIADBFAiEA3jOgXKub6rzL
A2pMDIPbMusaIHNBbnWVOBAjbCzV2pQCIGs3jvbFHl+MDoMeD5DXzQQu1NsgBeWT
BPztgzhn88op
-----END CERTIFICATE-----

No SNI:

192.168.1.8 (success)
$ echo | openssl s_client -showcerts -connect 192.168.1.8:443 2>/dev/null | openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            18:3b:ce:f9:77:c7:6d:2c:be:c7:fa:03:68:ba:c8:53
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = Caddy Local Authority - ECC Intermediate
        Validity
            Not Before: Sep 13 00:34:13 2020 GMT
            Not After : Sep 13 12:35:13 2020 GMT
        Subject: 
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:7a:25:da:f2:03:4f:2b:c9:54:da:3c:95:bb:39:
                    29:4b:0e:63:aa:d4:45:30:8f:e6:cf:22:f3:b7:28:
                    a6:5f:a5:cb:db:72:09:a8:f1:41:a5:7b:33:78:75:
                    51:a1:9c:9f:85:6d:40:69:34:6d:cf:7e:ff:9f:ba:
                    59:0c:34:d9:08
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Key Identifier: 
                37:27:EB:14:E3:4F:F2:59:90:57:3E:C5:5A:64:BE:C7:73:AA:ED:BA
            X509v3 Authority Key Identifier: 
                keyid:8B:BE:D9:7C:3E:32:B2:A9:24:D8:38:42:5F:7B:89:DE:CA:87:58:88

            X509v3 Subject Alternative Name: 
                IP Address:192.168.1.8
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:21:00:de:33:a0:5c:ab:9b:ea:bc:cb:03:6a:4c:0c:
         83:db:32:eb:1a:20:73:41:6e:75:95:38:10:23:6c:2c:d5:da:
         94:02:20:6b:37:8e:f6:c5:1e:5f:8c:0e:83:1e:0f:90:d7:cd:
         04:2e:d4:db:20:05:e5:93:04:fc:ed:83:38:67:f3:ca:29
-----BEGIN CERTIFICATE-----
MIIBtTCCAVugAwIBAgIQGDvO+XfHbSy+x/oDaLrIUzAKBggqhkjOPQQDAjAzMTEw
LwYDVQQDEyhDYWRkeSBMb2NhbCBBdXRob3JpdHkgLSBFQ0MgSW50ZXJtZWRpYXRl
MB4XDTIwMDkxMzAwMzQxM1oXDTIwMDkxMzEyMzUxM1owADBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABHol2vIDTyvJVNo8lbs5KUsOY6rURTCP5s8i87copl+ly9ty
CajxQaV7M3h1UaGcn4VtQGk0bc9+/5+6WQw02QijgYMwgYAwDgYDVR0PAQH/BAQD
AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUNyfr
FONP8lmQVz7FWmS+x3Oq7bowHwYDVR0jBBgwFoAUi77ZfD4ysqkk2DhCX3uJ3sqH
WIgwDwYDVR0RBAgwBocEwKgBCDAKBggqhkjOPQQDAgNIADBFAiEA3jOgXKub6rzL
A2pMDIPbMusaIHNBbnWVOBAjbCzV2pQCIGs3jvbFHl+MDoMeD5DXzQQu1NsgBeWT
BPztgzhn88op
-----END CERTIFICATE-----

curl output:

192.168.1.8 (success)
$ curl -v https://192.168.1.8
*   Trying 192.168.1.8:443...
* Connected to 192.168.1.8 (192.168.1.8) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 13 00:34:13 2020 GMT
*  expire date: Sep 13 12:35:13 2020 GMT
*  subjectAltName: host "192.168.1.8" matched cert's IP address!
*  issuer: CN=Caddy Local Authority - ECC Intermediate
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55db73a9a9f0)
> GET / HTTP/2
> Host: 192.168.1.8
> user-agent: curl/7.71.1
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200 
< server: Caddy
< content-length: 5
< date: Sun, 13 Sep 2020 02:30:56 GMT
< 
* Connection #0 to host 192.168.1.8 left intact
Hello

I didn’t test --network host or the other IPs, is the above sufficient? Let me know if you need anything else.

It seems that IP addresses qualify for automatic HTTPS, so a self-signed certificate is created (verified) for IP addresses to the site block, and implicit HTTP->HTTPS redirect setup.

However requests where the {host} is an IP address fail to actually establish an HTTPS connection unless the IP address matches the default_sni and that value is used in a site block so that an actual TLS cert exists to respond with?

I’m not sure how default_sni is set by Caddy (without explicit value), seems to be 127.0.0.1 on a host network (which 0.0.0.0 would map to and bind directive defaults to 0.0.0.0), but for some reason if not using the host network, it binds to the containers IP in the Docker network (172.17.0.2), perhaps because 127.0.0.1 would not be reachable outside of the container? So it’s whatever network interface IP the request arrives from as 0.0.0.0 covers both of those within the container? (thus is the default SNI is not fixed like the global setting default_sni would be?)

I assume that relying on SNI to get the certificate is why each site address has an individual cert each by filename for lookup, instead of by some site block ID with a SAN listing each site address that’s valid for the site block (where a default SNI would no longer be required?).

Caddy logs the failed TLS handshake:

TLS handshake error from 192.168.1.8:38092: no certificate available for '172.17.0.2'

I haven’t confirmed, but I’m assuming that 192.168.1.8 is the client IP address if it was from a user on the internet or another device on my LAN, and all that Caddy is aware of (for SNI assumptions) is network IPs that the container would respond with for 0.0.0.0, so while 192.168.1.8 may have a certificate for a site block it is associated with, without an SNI provided, Caddy doesn’t know how to look up the certificate file? Even if Caddy did know to look it up, the SAN in the certificate would be a mismatch?

{
  default_sni 192.168.1.42
}

192.168.1.8 {
  respond "Hello"
}

172.17.0.2 {
  respond "Bye"
}

No SNI:

192.168.1.8 (fail - SAN mismatch: 172.17.0.2)
$ echo | openssl s_client -showcerts -connect 192.168.1.8:443 2>/dev/null | openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            8b:4e:95:ff:2d:ce:e7:4b:ec:56:e7:47:ab:a3:f9:9a
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = Caddy Local Authority - ECC Intermediate
        Validity
            Not Before: Sep 13 06:07:31 2020 GMT
            Not After : Sep 13 18:08:31 2020 GMT
        Subject: 
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:96:4d:f1:e4:23:b1:81:d9:0f:ec:cf:d4:c1:de:
                    19:01:b8:13:bb:0b:35:8c:a4:7a:80:45:2d:3c:9f:
                    6a:99:ad:f1:aa:82:65:9b:3d:8b:40:77:7b:24:83:
                    37:3d:c4:72:40:84:80:a7:a2:1e:97:e6:a3:cc:6c:
                    f0:b2:ed:ee:b2
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Key Identifier: 
                95:4B:B7:FB:97:0C:CB:D3:01:E1:C8:A8:54:17:B7:14:6E:2E:67:CF
            X509v3 Authority Key Identifier: 
                keyid:8B:BE:D9:7C:3E:32:B2:A9:24:D8:38:42:5F:7B:89:DE:CA:87:58:88

            X509v3 Subject Alternative Name: 
                IP Address:172.17.0.2
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:20:55:53:59:f2:8d:50:41:2f:51:8e:6b:19:17:e9:
         fb:68:ea:8e:f9:07:8d:2d:e4:e1:b6:0b:77:7b:3a:de:79:9a:
         02:21:00:a4:b1:11:ec:55:c2:e3:e1:7f:77:01:47:dd:5e:b7:
         b3:f3:e8:d3:2e:e5:83:77:89:c1:bd:93:75:5c:01:0c:b4
-----BEGIN CERTIFICATE-----
MIIBtjCCAVygAwIBAgIRAItOlf8tzudL7FbnR6uj+ZowCgYIKoZIzj0EAwIwMzEx
MC8GA1UEAxMoQ2FkZHkgTG9jYWwgQXV0aG9yaXR5IC0gRUNDIEludGVybWVkaWF0
ZTAeFw0yMDA5MTMwNjA3MzFaFw0yMDA5MTMxODA4MzFaMAAwWTATBgcqhkjOPQIB
BggqhkjOPQMBBwNCAASWTfHkI7GB2Q/sz9TB3hkBuBO7CzWMpHqARS08n2qZrfGq
gmWbPYtAd3skgzc9xHJAhICnoh6X5qPMbPCy7e6yo4GDMIGAMA4GA1UdDwEB/wQE
AwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFJVL
t/uXDMvTAeHIqFQXtxRuLmfPMB8GA1UdIwQYMBaAFIu+2Xw+MrKpJNg4Ql97id7K
h1iIMA8GA1UdEQQIMAaHBKwRAAIwCgYIKoZIzj0EAwIDSAAwRQIgVVNZ8o1QQS9R
jmsZF+n7aOqO+QeNLeThtgt3ezreeZoCIQCksRHsVcLj4X93AUfdXrez8+jTLuWD
d4nBvZN1XAEMtA==
-----END CERTIFICATE-----

curl output:

192.168.1.8 (fail)
$ curl -v https://192.168.1.8
*   Trying 192.168.1.8:443...
* Connected to 192.168.1.8 (192.168.1.8) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 13 06:07:31 2020 GMT
*  expire date: Sep 13 18:08:31 2020 GMT
*  subjectAltName does not match 192.168.1.8
* SSL: no alternative certificate subject name matches target host name '192.168.1.8'
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
curl: (60) SSL: no alternative certificate subject name matches target host name '192.168.1.8'
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

SNI 192.168.1.8:

172.17.0.2 (fail - SAN mismatch: 192.168.1.8)
$ echo | openssl s_client -showcerts -servername 192.168.1.8 -connect 172.17.0.2:443 2>/dev/null | openssl x509 -text    
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            ab:74:ba:60:11:17:0a:22:7d:80:a0:fa:aa:18:4d:2e
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = Caddy Local Authority - ECC Intermediate
        Validity
            Not Before: Sep 13 06:07:31 2020 GMT
            Not After : Sep 13 18:08:31 2020 GMT
        Subject: 
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:04:05:1f:12:dc:b7:91:36:4d:c5:3b:a6:97:1e:
                    1c:2f:e4:05:f6:28:df:9e:66:75:47:8d:1d:8f:58:
                    07:44:84:4a:99:a9:29:18:fa:d9:c7:c3:b8:cd:8a:
                    c8:26:c7:71:89:eb:90:95:1f:85:41:7c:b2:7a:58:
                    f3:4a:09:88:b8
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Key Identifier: 
                C5:FD:1A:C3:BC:88:A6:CB:65:2E:BD:C8:74:DF:14:F2:61:08:9A:A2
            X509v3 Authority Key Identifier: 
                keyid:8B:BE:D9:7C:3E:32:B2:A9:24:D8:38:42:5F:7B:89:DE:CA:87:58:88

            X509v3 Subject Alternative Name: 
                IP Address:192.168.1.8
    Signature Algorithm: ecdsa-with-SHA256
         30:46:02:21:00:bd:1e:ad:90:7e:91:70:cb:6e:5e:f6:69:cd:
         08:54:8d:fd:62:f2:30:85:a5:85:c8:92:b8:6a:7b:2e:fc:ca:
         a7:02:21:00:f7:6f:6a:25:48:a7:e8:f3:b8:24:a5:bf:20:a2:
         09:ba:9e:41:81:f3:94:f8:d6:e7:fe:2b:e6:81:bc:a1:2e:91
-----BEGIN CERTIFICATE-----
MIIBtzCCAVygAwIBAgIRAKt0umARFwoifYCg+qoYTS4wCgYIKoZIzj0EAwIwMzEx
MC8GA1UEAxMoQ2FkZHkgTG9jYWwgQXV0aG9yaXR5IC0gRUNDIEludGVybWVkaWF0
ZTAeFw0yMDA5MTMwNjA3MzFaFw0yMDA5MTMxODA4MzFaMAAwWTATBgcqhkjOPQIB
BggqhkjOPQMBBwNCAAQEBR8S3LeRNk3FO6aXHhwv5AX2KN+eZnVHjR2PWAdEhEqZ
qSkY+tnHw7jNisgmx3GJ65CVH4VBfLJ6WPNKCYi4o4GDMIGAMA4GA1UdDwEB/wQE
AwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFMX9
GsO8iKbLZS69yHTfFPJhCJqiMB8GA1UdIwQYMBaAFIu+2Xw+MrKpJNg4Ql97id7K
h1iIMA8GA1UdEQQIMAaHBMCoAQgwCgYIKoZIzj0EAwIDSQAwRgIhAL0erZB+kXDL
bl72ac0IVI39YvIwhaWFyJK4ansu/MqnAiEA929qJUin6PO4JKW/IKIJup5BgfOU
+Nbn/ivmgbyhLpE=
-----END CERTIFICATE-----

SNI 192.168.1.42:

172.17.0.2 (fail - Unable to load certificate)
$ echo | openssl s_client -showcerts -servername 192.168.1.42 -connect 172.17.0.2:443 2>/dev/null | openssl x509 -text
unable to load certificate
139637896070464:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE

No SNI:

172.17.0.2 (success)
$ echo | openssl s_client -showcerts -connect 172.17.0.2:443 2>/dev/null | openssl x509 -text                          
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            8b:4e:95:ff:2d:ce:e7:4b:ec:56:e7:47:ab:a3:f9:9a
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = Caddy Local Authority - ECC Intermediate
        Validity
            Not Before: Sep 13 06:07:31 2020 GMT
            Not After : Sep 13 18:08:31 2020 GMT
        Subject: 
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:96:4d:f1:e4:23:b1:81:d9:0f:ec:cf:d4:c1:de:
                    19:01:b8:13:bb:0b:35:8c:a4:7a:80:45:2d:3c:9f:
                    6a:99:ad:f1:aa:82:65:9b:3d:8b:40:77:7b:24:83:
                    37:3d:c4:72:40:84:80:a7:a2:1e:97:e6:a3:cc:6c:
                    f0:b2:ed:ee:b2
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Key Identifier: 
                95:4B:B7:FB:97:0C:CB:D3:01:E1:C8:A8:54:17:B7:14:6E:2E:67:CF
            X509v3 Authority Key Identifier: 
                keyid:8B:BE:D9:7C:3E:32:B2:A9:24:D8:38:42:5F:7B:89:DE:CA:87:58:88

            X509v3 Subject Alternative Name: 
                IP Address:172.17.0.2
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:20:55:53:59:f2:8d:50:41:2f:51:8e:6b:19:17:e9:
         fb:68:ea:8e:f9:07:8d:2d:e4:e1:b6:0b:77:7b:3a:de:79:9a:
         02:21:00:a4:b1:11:ec:55:c2:e3:e1:7f:77:01:47:dd:5e:b7:
         b3:f3:e8:d3:2e:e5:83:77:89:c1:bd:93:75:5c:01:0c:b4
-----BEGIN CERTIFICATE-----
MIIBtjCCAVygAwIBAgIRAItOlf8tzudL7FbnR6uj+ZowCgYIKoZIzj0EAwIwMzEx
MC8GA1UEAxMoQ2FkZHkgTG9jYWwgQXV0aG9yaXR5IC0gRUNDIEludGVybWVkaWF0
ZTAeFw0yMDA5MTMwNjA3MzFaFw0yMDA5MTMxODA4MzFaMAAwWTATBgcqhkjOPQIB
BggqhkjOPQMBBwNCAASWTfHkI7GB2Q/sz9TB3hkBuBO7CzWMpHqARS08n2qZrfGq
gmWbPYtAd3skgzc9xHJAhICnoh6X5qPMbPCy7e6yo4GDMIGAMA4GA1UdDwEB/wQE
AwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFJVL
t/uXDMvTAeHIqFQXtxRuLmfPMB8GA1UdIwQYMBaAFIu+2Xw+MrKpJNg4Ql97id7K
h1iIMA8GA1UdEQQIMAaHBKwRAAIwCgYIKoZIzj0EAwIDSAAwRQIgVVNZ8o1QQS9R
jmsZF+n7aOqO+QeNLeThtgt3ezreeZoCIQCksRHsVcLj4X93AUfdXrez8+jTLuWD
d4nBvZN1XAEMtA==
-----END CERTIFICATE-----

curl output:

172.17.0.2
$ curl -v https://172.17.0.2
*   Trying 172.17.0.2:443...
* Connected to 172.17.0.2 (172.17.0.2) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Sep 13 06:07:31 2020 GMT
*  expire date: Sep 13 18:08:31 2020 GMT
*  subjectAltName: host "172.17.0.2" matched cert's IP address!
*  issuer: CN=Caddy Local Authority - ECC Intermediate
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x56396de0e9f0)
> GET / HTTP/2
> Host: 172.17.0.2
> user-agent: curl/7.71.1
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200 
< server: Caddy
< content-length: 3
< date: Sun, 13 Sep 2020 06:37:09 GMT
< 
* Connection #0 to host 172.17.0.2 left intact
Bye

Ok… so that confirms that SNI looks up a certificate, and that default_sni has no relevance at least with IPs if that has no match within a site block’s addresses. I added a third site block for 192.168.1.42 to see what happens with the certificate for it, but continued to see 172.17.0.2 SAN, same when adding 192.168.1.42 to the 192.168.1.8 site block, 192.168.1.8 would continue to return the 172.17.0.2 SAN/cert.

EDIT: I thought that default_sni only didn’t work if the default SNI that setting overrides wasn’t in a site address for the same block, turns out that using the 172.17.0.2 for a different site block is what prevented default_sni from taking affect.

{
  default_sni 192.168.1.8
}

192.168.1.8 {
  respond "Hello"
}

172.17.0.2 {
  respond "Bye"
}

The above fails like earlier examples as the default_sni doesn’t override 172.17.0.2 which is returned as SAN still.

{
  default_sni 192.168.1.8
}

192.168.1.8 {
  respond "Hello"
}

Success with overriding, can use default_sni 192.168.1.42 and it will appear as the SAN now (provided it’s added as a site address for a site block too, otherwise will fail to load a certificate).


TL;DR:

  • Caddy will respond to IP addresses that are used as site addresses for site blocks correctly over HTTP.
  • Caddy relies on SNI to load TLS certificate, where each certificate has single SAN.
  • IP addresses will register individual certs with their IP as a SAN, but as SNI is typically not provided with IP address requests, the TLS cert loaded is dependent on the default SNI fallback value.

If Caddy responds to the correct site block over HTTP without SNI, why does it rely on SNI to load a TLS certificate? Is it possible to use that same information to look up a certificate as fallback, rather than whatever default_sni is set to? (which can only use a single address?)

Feel free to ignore the lengthy two responses above (or just look at the summary TLDR).

So the certificates that are generated for IP addresses that don’t match whatever default_sni is, will not ever be used? (at least when SNI is omitted like with browsers as you mention). But the clients would avoid failing if Caddy was able to return the certificate it generated for that IP address?

Understandably the best solution is to use FQDN site addresses setup to resolve to the IPs instead. At least it’s clear now why I was getting confused trying out HTTPS via IP address over another device on the LAN :smiley:

Thanks!


EDIT: Just tested Chrome after all that, and was surprised that 172.17.0.2 still gave an insecure error page. Turns out I carried the tests out with 2.1.1 of Caddy. Hopefully that didn’t ruin the test results above. Removed persisted certs and ran with 2.2.0-RC.1, Chrome accepts 172.17.0.2 fine, 192.168.1.8 fails due to SAN mismatch of course.