HAProxy redirect port and mask url - haproxy

I have a couple of webservers that are reachable directly through the following URL:
https://abcd.example.com:8445/desktop/container/landing.jsp?locale=en_US
https://wxyz.example.com:8445/desktop/container/landing.jsp?locale=en_US
I need to use HAProxy to loadbalance between the two and use the following URLs instead when hitting the frontend:
http://1234.example.com/desktop/container/landing.jsp?locale=en_US
or
https://1234.example.com:8445/desktop/container/landing.jsp?locale=en_US
So other requirements beside the two above:
If initial traffic is port 80, convert to port 8445
Mask the URL so that on the browser while it redirected to https and port to 8445, the host remains intact, like so: https://1234.example.com:8445/desktop/container/landing.jsp?locale=en_US
Here's my config so far:
frontend WebApp_frontend
mode http
bind 10.4.34.11:80
acl is80 dst_port 80
http-request set-uri https://%[req.hdr(Host)]:8445%[path]?%[query] if is80
default_backend WebApp-backend
backend WebApp_backend
description WebApp
balance roundrobin
mode http
server webserver1 10.2.89.222:8445 check inter 5s fall 3 rise 5 downinter 1m ssl verify none
server webserver2 10.4.89.223:8445 check inter 5s fall 3 rise 5 downinter 1m ssl verify none
The problem I'm facing right now is that when you access the frontend, HAProxy will redirect you to any of the webservers and force your client to hit the webserver directly instead of through the HAProxy. I need the connection to remain through the HAProxy.

If all your application is doing is redirecting to HTTPs then you should probably just handle that directly within HAProxy. You might want to also explore whether your application supports X-Forwarded-Proto and X-Forwarded-Host.
Another option is you can have HAProxy rewrite the redirects from the backend application to the hostname you choose. Using HAProxy 2.1 you would do something like this:
http-response replace-header location https?://[^:/]*(:?[0-9]+/.*) https://1234.example.com\1 if { status 301:302 }

Related

HAProxy redirect one URL into another

I’m quite new to HAProxy and have what I believe to be a simple use-case:
I want to redirect requests made into my KVM host --> URL of the guest VMs.
In my case the redirects are for several VMs that run HTTPS content.
Example:
-- HAProxy is running on the KVM host (10.10.10.5 - ansout.mine.local)
-- HTTPS guest VM running on KVM (172.10.10.5 - ans.lab.local)
How can I make a request from a client (on the KVM network) to ‘http://ansout.mine.local’ and redirect it into, 'https://ans.lab.local'
It would seem I need to use the ‘http-request redirect’ function in HAProxy but I still can’t wrap my head around it.
Could anyone one kindly provide some pointers on how to achieve the example above?
Many thanks in advance.
I assume that the client then should connect directly to ans.lab.local.
listen http-in
bind :80
log stdout format raw daemon
mode http
option httplog
tcp-request inspect-delay 5s
tcp-request content accept if HTTP
timeout client 5s
timeout connect 30s
timeout server 30s
http-request redirect code 301 location https://ans.lab.local if { hdr(host) -i ansout.mine.local }
If you have several hosts which you want to redirect please take a look into HAProxy Maps.

how to prevent 502 status code as response by haproxy as load balancer

I have 3 server:
server (A)= a nginx(port 80) as reverse proxy to kestler (5000 port)
server (B)= a nginx(port 80) as reverse proxy to kestler (5000 port)
server (C)= a HAProxy as load balancer for port 80 of server (A) and (B)
and server A & B are quite similar.
every things works very well and haproxy forwards requests to server (A) & (B), but if kestrel in one of servers (e.g. A) be killed, nginx respond 502 bad gateway error and haproxy not detect this issue and still redirect requests to it, and this is mistake! it must redirect requests to server (B) in this time.
global
log 127.0.0.1 local2 info
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
option redispatch
retries 3
timeout connect 5s
timeout client 50s
timeout server 50s
stats enable
stats hide-version
stats auth admin:admin
stats refresh 10s
stats uri /stat?stats
frontend http_front
bind *:80
mode http
option httpclose
option forwardfor
reqadd X-Forwarded-Proto:\ http
default_backend http_back
backend http_back
balance roundrobin
mode http
cookie SERVERID insert indirect nocache
server ServerA 192.168.1.2:80 check cookie ServerA
server ServerB 192.168.1.3:80 check cookie ServerB
How Can I resolve this issue?
thanks very much.
You are only checking whether nginx is running, not whether the application is healthy enough to use.
In the backend, add option httpchk.
option httpchk GET /some/path HTTP/1.1\r\nHost:\ example.com
Replace some path with a path that will prove whether the application is usable on that server if it returns 200 OK (or any 2xx or 3xx response), and replace example.com with the HTTP Host header the application expects.
option httpchk
By default, server health checks only consist in trying to establish a TCP connection. When option httpchk is specified, a complete HTTP request is sent once the TCP connection is established, and responses 2xx and 3xx are
considered valid, while all other ones indicate a server failure, including the lack of any response.
This will mark the server as unhealthy if the app is not healthy, so HAProxy will stop sending traffic to it. You will want to configure a check interval for each server using inter and downinter and fastinter options on each server entey to specify how often HAProxy should perform the check.

Transmission Torrent behind HAProxy - HTTP Response Header used as session identifier and stickiness token

I've been trying, and failing so far, to run Transmission behind HAProxy.
If I just add a new backend and route traffic as follows:
frontend http-in
bind *:80
reqadd X-Forwarded-Proto:\ http
acl host1 hdr_end(host) -i web.host1.host
use_backend apache_backend if host1
acl transmission_host hdr_end(host) -i transmission.host1.host
use_backend transmission_backend if transmission_host
Then I get a 409 conflict error stating I have an invalid session-id header. That's pretty obvious and expected since there's a proxy in the middle.
I thought of recompiling transmission to get rid of the check, but decided in the end to face the challenge of learning a bit more of HAProxy. What did I have in mind?
Client reaches HAProxy
HAProxy connects to transmission-daemon
Daemon replies with X-Transmission-Session-Id
HAProxy stores the Session-Id somehow and replaces Session-Id sent by the client with the one captured by HAProxy.
After a lot of Googling and playing with the settings, I got an almost working configuration:
frontend http-in
bind *:80
reqadd X-Forwarded-Proto:\ http
capture response header X-Transmission-Session-Id len 48
acl host1 hdr_end(host) -i web.host1.host
use_backend apache_backend if host1
acl transmission_host hdr_end(host) -i transmission.host1.host
use_backend transmission_backend if transmission_host
backend transmission_backend
mode http
http-request set-header X-Transmission-Session-Id %hs
server transmission-daemon transmission.intranet:9091
My configuration examples are summarized.
It works, sort of. I get a login prompt for transmission, but the page loads incredibly slow. I'm more than 10 minutes in and still don't have it fully loaded.
More pages go through this proxy: HTTP, HTTPS, TCP, some load balanced, some set as fail-overs. They all load normally and fast. If I connect directly to the transmission-daemon server, it loads fast as well.
I'll keep looking around.
Any ideas?
Thanks in advance!
3 years later,
from what I've seen in https://gist.github.com/yuezhu/93184b8d8d9f7d0ada0a186cbcda9273
you should capture request and response in frontend http-in,
I didn't dug much more, but the backend seems to need
stick-table type binary len 48 size 30k expire 30m
stick store-response hdr(X-Transmission-Session-Id)
stick on hdr(X-Transmission-Session-Id)
to work

haproxy: set timeout if <condition>

The question seems to be quite straight and easy, however I have not been able to find a proper answer.
In haproxy I have 1 backend, say:
backend-1
and 2 frontends, say:
frontend-1
frontend-2
In the backend stanza I want to set a "timeout server" parameter, but, only if the connection comes from frontend-1.
As I didn't find anything I tried to figure it out myself:
backend backend-1
bind *:80
option <blahblah_option>
timeout server 1d if frontend frontend-1
This syntax does not work, and I am mentioning it to let understand what I am trying to achieve.
This is not doable yet in HAProxy.
Later, you will be able to set timeouts using tcp-request and http-request rules.
What we usually do to workaround this for now, is that we setup 2 backends using the same parameters, but different timeout servers.
This is useful when a few urls only deserve a long server timeout.
Edit followup your comment about multiple health checks:
Well, that's why the server's 'track' directive exists:
backend my_app
server srv1 10.0.0.1:80 check
backend my_app_longtime
server srv1 10.0.0.1:80 track my_app/srv1
In the conf above, the server in my_app_longtime backend won't be checked. That said, it will follow up the same state than srv1 in the backend my_app.
Baptiste
Baptiste
I did it like this and it worked. It made it possible to extend timeout on specific app urls, which are more time consuming. Used that trace health check - thanks Babtiste.
frontend www-http
bind 10.0.0.1:80
default_backend app
acl long_url path_beg -i /long_url
use_backend app-extended if long_url
backend app
server web-1 10.0.0.2:80 check
backend app-extended
server web-1 10.0.0.2:80 trace app/web-1
timeout server 10m

Haproxy ability for multiple port 80, 443 frontends

I have the need to have both layer7 and layer4. An api where i divert requests two 2 different backends. one backend for GET requests and one backend for PUT,GET & DELETE requests. That being my layer 7 front end.
The layer4 front to handle websites who make the api requests. They just split round robin.
Layer7 was working consistently before I add in this layer4 section, ie just did our loadbalancing for the api. As i migrate the websites w/ the layer4 frontend, api requests, ie layer7, get lost sometimes but not always.
As you can see, sometimes request is lost, sometimes works:
[richv#lb2 ~]$ curl api
curl: (52) Empty reply from server <-- this is not ok, http 503
[richv#lb2 ~]$ curl api
{"error_code":256,"error_message":"No Site specified"} <-- this is ok, cause didnt give all the headers.
Front ends are:
frontend layer7-http-listener
bind *:80
bind *:443 ssl crt /etc/httpd/certs/haproxy.pem
mode http
option httpclose
option httplog
option forwardfor
option accept-invalid-http-request
frontend layer4-listener
bind *:80 transparent
bind *:443 transparent
bind *:3306
mode tcp
option tcplog