I have a java application in Tomcat which does a redirect based on the host header. To get to this application we must go through nginx and then haproxy. Nginx sets a host request header to match the service name, and then sends the request off to haproxy. Haproxy uses that host request header to route the request to the correct service. For example:
Nginx has a location rule for /app and sets a Host header of app.internal.lan so we can find the app. It then passes the request off to http://app.internal.lan/app. Something like
HAProxy sees the Host header is set to app.internal.lan and routes to the correct backend rule (which goes to Tomcat)
I notice when I go through haproxy without SSL everything works fine. That is, after the user logs in they are directed to https://example.com/app/welcome.do as I would expect.
However, when I enable SSL in HAProxy, my redirect suddenly wants to take me to https://app.internal.lan/app/welcome.do.
I have confirmed that HAProxy is not passing the header the same way it does when using HTTP. If I add http-request set-header Host example.com into my backend rule it works as expected.
My question is: is there any way to preserve the Host header when using SSL termination on HAProxy? Why does the redirect work via HTTP, but not HTTPS? Or maybe the question is, why does the Host header get lost when using SSL.
Haproxy doesn’t strip the Host header, something else must be going on here. Can you post the haproxy configuration, as complete as possible?
If you enable SSL on haproxy, do you still connect via nginx? How does that work, because nginx either forwards only TCP there, so proxy_set_header won’t work, or if the browser connects directly to haproxy, than of course proxy_set_header doesn’t work either because nginx is not even involved.
Hi @lukastribus. Yes, if I use SSL on haproxy I still connect via nginx. I have several applications that work fine this way, it’s only this one particular web app which does the redirect after login.
Like I said, haproxy doesn’t strip the Host header. Most likely nginx does not send it, which is why it only works when you manually set it in haproxy.
Test it with curl against haproxy directly or verify the request in debug mode.
But if nginx was the problem, it would happen when using haproxy via http. The only variable here is that haproxy has been changed to add ssl crt /etc/haproxy/haproxy.pem to the frontend. I don’t have the add the set-header option when I use haproxy on http. The redirect works as expected.
Another thing that doesn’t make sense: nginx sets the Host header to app.internal.lan. You than expect that haproxy maintains that Host header, but your “fix” is to reset the Host header in haproxy to example.com, instead of app.internal.lan.
If you believe haproxy strips the host header, you configuration workaround would have to look like this:
I tend to agree with this statement, and am also wondering how the host header stays as example.com when using HTTP (because even over HTTP nginx is changing the header to app.internal.lan). As you can see in my logging statement above, I should be seeing headers in my logs ( %hr\ %hs\), however, I don’t see them.
It is really strange that I don’t have to set http-request set-header Host app.internal.lan when using HTTP in haproxy, and the redirect still works fine (even though nginx has changed the header).
Can you please advise the best way to test this using curl? I’d like to see exactly where the header is getting change. I appreciate all of the help.
I suggest you enable debug mode in haproxy (start it from the command line be specifying -d), so you can see what nginx actually sends towards haproxy, in both http and https mode. You should also be able to see how the tomcat backend reacts.
Since the redirect happens after the login, its probably difficult to simulate using curl.