9

I am exploring the use of HAProxy as a balancer in front of a set of web apis that run on IIS.

  • node1.myapp.mycompany.com
  • node2.myapp.mycomapny.com

We are currently using Host Headers to correctly resolve the right web application on IIS. For example, we may have otherapp.mycompany.com running on the same server/port, but using Host Headers IIS knows which one to serve up.

My initial attempt at HAProxy left me with 404 errors, because I was not including the host headers in my request, and so IIS was serving back the default site bound to the given IP, and not resolving by host name.

The fix left me with something like this:

frontend localnodes
    bind *:80
    mode http
    default_backend nodes

backend nodes
    mode http
    balance roundrobin
    option forwardfor
    reqirep ^Host: Host:\ node1.myapp.mycompany.com
    server web01 node1.myapp.mycompany.com:80

This works great for a single backend, but I am left scracthing my head on how to include the correct host headers depending on which backend is serving up the request:

backend nodes
    mode http
    balance roundrobin
    option forwardfor
    reqirep ^Host: Host:\ node1.myapp.mycompany.com
    server web01 node1.myapp.mycompany.com:80
    server web02 node2.myapp.mycompany.com:80

The above does not work whenever node2 is used because it doesn't resolve correctly in IIS (node2 in this case is on a different server, and therefore different IP. In fact, if they were running on the same server/ip I suspect the request work "work", but they would all be served by node1 per the host header).

  • Is it possible to set the host based on the url of the backend used to serve up the request?
  • If so, this implies my checks also need to provide the correct host header based on backend, how would that be done?

Edit: Am using HA-Proxy version 1.7.9 2017/08/18

Let me give this just a little more background. We used to have just myapp.mycompany.com serving up api requests. We need to expand it. Our clients will still call myapp.mycompany.com, but that will just point to the HAProxy, which will balance it out to node1.myapp.mycompany.com and node2.myapp.mycompany.com. Our current server configurations have us binding a single IP address on each server, so we use host headers to resolve.

6
  • Which version are you using?
    – gxx
    Oct 4, 2017 at 15:36
  • @gf_ 1.7.9 from 2017/08/18
    – Matt
    Oct 4, 2017 at 15:40
  • Do I understand correctly, that node{1,2}.myapp.mycompany.com are the HTTP host headers, the clients are using? If so, why is node{1,2} relevant, why is it not only myapp.mycompany.com? This would simplify things a lot, IMHO.
    – gxx
    Oct 4, 2017 at 15:43
  • So, from the clients perspective, they will be calling myapp.mycompany.com. However, the webapps themselves are hosted with the additional subdomain. This is hold over from the current networking structure where we bind multiple apps to the same IP/port and need the headers to differentiate. Does that answer your question?
    – Matt
    Oct 4, 2017 at 15:51
  • @gf_ added some additional clarifying info in the question at the bottom
    – Matt
    Oct 4, 2017 at 15:57

2 Answers 2

17

I'm not sure if the following will work, and can't test right now, but maybe this is still helpful. (I'll have a look again later with some more time):

Solution 1:

backend nodes
    mode http
    balance roundrobin
    option forwardfor
    http-request set-header Host node1.myapp.mycompany.com if { srv_id 1 }
    http-request set-header Host node2.myapp.mycompany.com if { srv_id 2 }
    server web01 node1.myapp.mycompany.com:80
    server web02 node2.myapp.mycompany.com:80

Solution 2:

Note This one is officially not recommended. Read the comment on http-send-name-header: it has been reported that this directive is currently being used as a way to overwrite the Host header field in outgoing requests; while this trick has been known to work as a side effect of the feature for some time, it is not officially supported and might possibly not work anymore in a future version depending on the technical difficulties this feature induces... [Credits to rustyx.]

backend nodes
    mode http
    balance roundrobin
    option forwardfor
    http-send-name-header Host
    server node1.myapp.mycompany.com node1.myapp.mycompany.com:80
    server node1.myapp.mycompany.com node2.myapp.mycompany.com:80
12
  • 1
    Thanks, your 2nd example did the trick for me. Couldn't get the first one to work, though I don't remember what the error was right off hand (I think something to do with the conditional expression).
    – Matt
    Oct 16, 2017 at 18:49
  • @Matt Thanks.. could you still get the "proper" error message? I'm curious..
    – gxx
    Oct 16, 2017 at 20:40
  • 1
    @gf_ none of these solutions work for me. In the first solution, it never sets the header. If I remove de if then it works but I have two backend servers so I need the if. The second solution does not add the Host and I get a 404 because IIS cannot find the right binding. Could you make Solution 1 work? Jul 6, 2018 at 15:25
  • 1
    @gf_ turns out that http-send-name-header Host did work. I just didn't configure it correctly, I was using server mysite1Server node1.mysite.com:443 check ssl verify none and it should have been server node1.mysite.com node1.mysite.com:443 check ssl verify none. Sorry for wasting your time. Might be a good idea to remove solution 1 from the answer because that one does not seem to be working. Jul 7, 2018 at 18:20
  • 1
    Solution 2 is officially not recommended. Read the comment on http-send-name-header: it has been reported that this directive is currently being used as a way to overwrite the Host header field in outgoing requests; while this trick has been known to work as a side effect of the feature for some time, it is not officially supported and might possibly not work anymore in a future version depending on the technical difficulties this feature induces...
    – rustyx
    Jun 28, 2021 at 8:49
1

I want to complement gf_ answer. So the idea of his answer is to add a custom Host header which value is the source hostname itself. In solution one, basically, he set the header manually with a condition from srv_id thing.

The second on shortcut the first solution by sending the name of the host as a Host header.

But in his solution, he doesn't mention that it only set-header, if the header is already there it can't replace the existing header, so if your case need to replace Host header, you can do somethinghing like this

backend nodes
    mode http
    balance roundrobin
    option forwardfor
    http-request replace-header Host node1.myapp.mycompany.com node1.myapp.mycompany.com if { srv_id 1 }
    http-request replace-header Host node2.myapp.mycompany.com node2.myapp.mycompany.com if { srv_id 2 }
    server web01 node1.myapp.mycompany.com:80
    server web02 node2.myapp.mycompany.com:80
1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .