Reverse proxy SNI configuration

1. The problem I’m having:

I have a lots of those errors in log even all seems to be working good…
My setup is bad and clunky and I want to use SNI but I don’t know how to do so…

How can I configure SNI so certificates can be generated fully on my app server ?
Or how do I use SNI ?

2. Error messages and/or full log output:

Dec 02 17:23:47 host caddy[497]: {"level":"error","ts":1733156627.6308937,"logger":"http.handlers.reverse_proxy","msg":"aborting with incomplete response","upstream":"mysuperserver.com:443","duration":0.464332865,"request":{"remote_ip":"1.2.3.4","remote_port":"44984","client_ip":"1.2.3.4","proto":"HTTP/2.0","method":"GET","host":"mysuperserver.quest","uri":"/Playback/BitrateTest?Size=500000","headers":{"Accept-Encoding":["gzip, deflate, br, zstd"],"Te":["trailers"],"Sec-Gpc":["1"],"Sec-Fetch-Dest":["empty"],"Accept-Language":["en-US,en;q=0.5"],"Sec-Fetch-Site":["same-origin"],"User-Agent":["Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0"],"X-Forwarded-For":["192.168.1.2"],"Cache-Control":["no-cache, no-store"],"Authorization":["REDACTED"],"Sec-Fetch-Mode":["cors"],"X-Forwarded-Proto":["https"],"Accept":["*/*"],"Dnt":["1"],"X-Forwarded-Host":["mysuperserver.quest"]},"tls":{"resumed":false,"version":772,"cipher_suite":4867,"proto":"h2","server_name":"mysuperserver.quest"}},"error":"reading: context canceled"}
Dec 02 17:27:47 host caddy[497]: {"level":"info","ts":1733156867.219989,"logger":"http.log.access","msg":"handled request","request":{"remote_ip":"1.2.3.4","remote_port":"58698","client_ip":"1.2.3.4","proto":"HTTP/1.1","method":"GET","host":"1.2.3.4","uri":"/","headers":{"User-Agent":["Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"],"Content-Length":["0"]}},"bytes_read":0,"user_id":"","duration":0.000304114,"size":0,"status":308,"resp_headers":{"Content-Type":[],"Server":["Caddy"],"Connection":["close"],"Location":["https://1.2.3.4/"]}}

3. Caddy version:

v2.8.4

4. How I installed and ran Caddy:

sudo apt install caddy

a. System environment:

so I generate certificates in “server 2 app” with mysuperserver.quest but as self-signed.
in caddy “server 1 reverse” I apply caddy config reverse on domain mysuperserver.quest (see below) with tls skip verify
and I add in my /etc/hosts 192.168.1.2 mysuperserver.quest

 ________      __________________      ______________
| ROUTER | -> | server 1 reverse | -> | server 2 app |
|________|    |__________________|    |______________|

d. My complete Caddy config:

(logging) {
    log {
        output file /var/log/caddy/access.log
    }
}

(header) {
        header {
                Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
		#too strong => Content-Security-Policy "default-src https:"
		Content-Security-Policy "default-src https: 'unsafe-inline'"
                X-Robots-Tag "none;"
                Referrer-Policy "strict-origin-when-cross-origin"
                Cache-Control "public, max-age=15, must-revalidate"
                Permissions-Policy "accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'self'; camera 'none'; encrypted-media 'none'; fullscreen 'self'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture *; speaker 'none'; sync-xhr 'none'; usb 'none'; vr 'none'"
                Server "No."
        }
}

mysuperserver.quest {
        import logging
        import header
        reverse_proxy https://mysuperserver.quest {
		transport http {
                        tls
                        tls_insecure_skip_verify
                }
	}
}

1 Like

Howdy @Guiz!

Generally we advise against this kind of security theatre. Any headers that are actually required for the secure function of the upstream app should be handled by the upstream app itself. I would remove all of this unless you have a very good reason for any of it.

That second log entry is just a 308 redirect from HTTP to HTTPS. That’s good, normal behaviour.

The first entry looks to me like a closed stream. Maybe a video stream of some kind. If that’s the case, it’s probably expected behaviour between a streaming server and a video player client, and I probably wouldn’t worry about it unless you experience some kind of issue in the client.

Server Name Indication (SNI) is a means to signal what domain name you’re trying to connect to so that a web server can select and return the appropriate HTTPS certificate for that website.

Caddy already uses SNI when connecting to a backend server (e.g. reverse_proxy https://example.com should send SNI for “example.com”). So, in your case, it should already be doing that. If it isn’t correct for some reason, you can manually specify SNI with the tls_server_name option in your reverse_proxy. More details are in the documentation:

https://caddyserver.com/docs/caddyfile/directives/reverse_proxy#tls_server_name

SNI is unrelated to the process of acquiring trusted HTTPS certificates.

1 Like

Thanks a lot for your answer !!

Got it about the header “theatre”…

And I get to understand better what is SNI and what it does with your explanation.

So the way I use /etc/hosts to trick the reverse proxy into finding the local app server and the local app server having self-signed certificates are not bad practice in your opinion ?

I definitely wouldn’t call it bad practice.

Personally I prefer to put these kinds of things in private DNS. I find managing /etc/hosts to be a little tedious if you don’t have some kind of configuration management plane like Ansible or NixOS deployments, whereas putting all my overrides in my router’s configuration keeps it centralised and makes it available to everything in the LAN that might need it.

But, ultimately, all you’re doing is taking advantage of the DNS resolution stack of the host itself to point a name at a specific IP. If it works for you - well, that’s one of the reasons /etc/hosts exists.

I have tried your solution via local DNS but I run into errors like SSL certificate problem: self-signed certificate in certificate chain

which was not the case with the /etc/hosts

how is your configuration to avoid such errors ?

I don’t have any special configuration for Caddy, it’s the exact same config that would otherwise work with /etc/hosts.

I simply replicate the same DNS responses via local DNS. My router of choice is OPNsense, and my host overrides are in Unbound.

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