Whenever you are proxying to a https backend, there are two pitfalls:
- The
Host
header, which gets inherited from the connection/vhost by default - The TLS SNI/server name, which sets the server name in the initial TLS handshakes with the upstream, basically. That’s before any headers (like the
Host
header) even get sent
Excerpts from reverse_proxy (Caddyfile directive) — Caddy Documentation
When proxying over HTTPS, you may need to override the
Host
header such that it matches the TLS SNI value, which is used by servers for routing and certificate selection. See the HTTPS section below for more details.
and
Since (most) headers retain their original value when being proxied, it is often necessary to override the
Host
header with the configured upstream address when proxying to HTTPS, such that theHost
header matches the TLS ServerName value. For example:reverse_proxy https://example.com { header_up Host {upstream_hostport} }
If your config looks like
matice.com {
reverse_proxy https://216.108.230.119
}
then Caddy keeps the Host
header value set to matice.com
, but the TLS server name will be set to 216.108.230.119
, to which your upstream server says “nope”
Your workaround (putting the IP+hostname into the hosts file and pointing Caddy to the hostname) works, because Caddy will then use matice.com
as TLS server name (SN)
Instead of that, you could also just make Caddy that you don’t want to read the SN from the upstream target (in your case IP) and override it:
matice.com {
reverse_proxy https://216.108.230.119 {
transport http {
tls_server_name matice.com
}
}
}
Strictly speaking, you could also drop that leading https://
in your upstream target, because
- tls uses HTTPS with the backend. This will be enabled automatically if you specify backends using the
https://
scheme or port:443
, or if any of the belowtls_*
options are configured.
but feel free to keep it for better readability or whatever /shrug
The actual is tls_server_name
option is documented here and here