Placeholders in tls/server_name

Hi.

I would like to configure a reverse-proxy with a wildcard domain and sni support.
Is it possible to use placeholders in tls/server_name, like http.request.host? I really don’t want to configure a route for each backend - it would elemintate all the benefits of the wildcard domain.

{
    "@id": "wildcard-apps-mydomain-com",
    "handle": [
        {
            "handler": "subroute",
            "routes": [
                {
                    "handle": [
                        {
                            "handler": "reverse_proxy",
                            "headers": {
                                "request": {
                                    "set": {
                                        "Host": [
                                            "{http.request.host}"
                                        ],
                                        "X-Real-Ip": [
                                            "{http.request.remote.host}"
                                        ]
                                    }
                                }
                            },
                            "transport": {
                                "protocol": "http",
                                "tls": {
                                    "server_name": "{http.request.host}"
                                }
                            },
                            "upstreams": [
                                {
                                    "dial": "10.0.0.42:443"
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ],
    "match": [
        {
            "host": [
                "*.apps.mydomain.com"
            ]
        }
    ]
}

It seems that caddy does not convert the placeholders into their corresponding values. This is an answer of a backend:

{"level":"error","ts":1598120557.7658117,"logger":"http.log.error","msg":"x509: certificate is valid for *.apps.mydomain.com, not {http.request.host}","request":{"method":"HEAD","uri":"/","proto":"HTTP/2.0","remote_addr":"10.0.0.107:64103","host":"abc.apps.mydomain.com","headers":{"User-Agent":["curl/7.64.1"],"Accept":["*/*"]},"tls":{"resumed":false,"version":771,"ciphersuite":52393,"proto":"h2","proto_mutual":true,"server_name":"abc.apps.mydomain.com"}},"duration":0.009521772,"status":502,"err_id":"2ugft70nu","err_trace":"reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:411)"}

Ah, I actually tried to make this work when I first implemented the TLS client in the HTTP transport of the reverse proxy. But I got stuck and didn’t want it to block continued development, so I gave up for the time being.

The problem is that the TLS config is generated at server startup, rather than at every request, for efficiency.

We could make a new TLS config (technically a Go std lib *crypto/tls.Config value) at every request, but that’s not very efficient, so it will slow down busy servers (pretty significantly; there’s a lot of encoding/decoding that goes on to load certificates and stuff, so lots of allocations).

If an efficient way to set the ServerName is discovered, we should do it. I won’t be able to look into this for a while but if you find a way then we can do it quickly. Here is the relevant code:

Edit: I forgot about this but there’s a Clone() method that could make this work without too much trouble. It makes at least one allocation (for the new Config value) but that’s probably acceptable. We might even be able to optimize it so that it only happens when { is detected in the ServerName. Want to submit a PR?

1 Like

Here’s a related issue asking for this as well

https://github.com/caddyserver/caddy/issues/3425

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