Send real Host header in httpchk requests

Hi, folks!
Is there is a way to send real backend address as a Host header in the httpchk requests? We are currently using HTTP 1.0, but would like to switch to HTTP 1.1 and sending meaningful Host header is a mast in your case. Here is our current backend section of the config:

backend apiservers
  balance                 leastconn
  mode                    http
  option                  httpchk GET /healthz HTTP/1.0\r\nAuthorization:\ Bearer\ SOME_TOKEN_HERE
  http-check              disable-on-404
  http-check              expect rstring ^ok
  server                  core1 core1.cloud:443 ssl check
  server                  core2 core2.cloud:443 ssl check
  server                  core3 core3.cloud:443 ssl check

Options like http-request add-header Host %[src] and http-send-name-header Host in the backend section seem not affect httpchk mechanism. Any ideas?

No, it’s not possible to do so with health-checks.

Use the Host header a browser would send, when talking to your application.

I have 3 backends, they are on a different servers. Host will differ for each one.

You can define the Hostname per backend, by providing the Host header in the httpchk option, just like you do with the Authorization header.

It is not possible per server though, like I said.

I see… Actually, that was the fist thing I tested. But it looks like that per server Host header is a good case for a feature request. Imagine a WEB server with several virtual hosts and you need to monitor some applications on that server. Without a real Host header you can’t perform live checks on them.

I don’t follow. Especially when you have virtual hosting, all servers will have to serve all vhosts, so I really don’t see why you’d need individual Host headers based on the hostname of the server, as opposed to a generic health checking hostname or a default domain, that doesn’t require a Host header.

A browser doesn’t know about the different backend server, it will always send the same Host header, backend servers will serve the same content (unless the setup is missconfigured), so I don’t get the point.

However, this is not the first time this comes up and I am sure there are actual, valid use cases for this.

Here is a thread from the mailing list:
https://www.mail-archive.com/haproxy@formilux.org/msg22754.html

There are other - more complex - ways to do this currently, for example with external health check agents or by tracking the servers health in a dedicated backend.

However this is not an easy fix, as Willy explains in the mentioned thread. And it won’t happen on it’s own, somebody needs to do the actual work to develop this (without breaking existing functionality).

We are using HAProxy for balancing Kubernetes APIServers. APIServer will refuse all requests with no Host header, if I switch to HTTP 1.1.

Doesn’t explain why it can’t be the same Host header for every backend server, which was my entire point.

I have no idea what to use to be “correct” and not get rejected some day after next APIServer update.

The Host header your application actually uses? After all, if your actual application doesn’t work, what’s the point?

Have no clue about the real Host header used by native Kubernetes components. All of them use SSL and we found no way to sniff the data. But curl will send ‘Host: core1.cloud’ and that does the business. We, probably, can get headers from HAProxy because we terminate SSL and therefore HAProxy can see what sent by components.

If you terminate SSL you have the hostname right there in the certificate. You can also log Host header or SNI fields in haproxy.

We will see what we have and I will come back later.
P.S. Thanks for your support. We found, that HAProxy is extremely capable thing (and the only one to fulfil our requirements in transparent balancing of APIservers, especially in pair with Keepalived). Now we can see, that support is at same level :slight_smile: .

1 Like

We were lucky to find some of our old sniffs. Here is the full request:

GET /api/v1/services?limit=500&resourceVersion=0 HTTP/1.1\r\n
Host: core1.cloud:8080\r\n
User-Agent: kubelet/v1.9.3 (linux/amd64) kubernetes/d283541\r\n
Accept: application/vnd.kubernetes.protobuf, */*\r\n
Accept-Encoding: gzip\r\n`
\r\n

This looks to be a kubelet request of some kind.