HAProxy - The Reliable, High Performance TCP/HTTP Load Balancer

mail

redirect / rewrite

redirect or rewrite ? Learn the difference

When administering a web server or a reverse proxy, you'll often be asked to "redirect foo to bar". Most of the time, this just means that the requester expects —after typing foo in the address bar of his web browser— the page bar to appear. They'll say "redirect", even though this means 2 different actions on the web server / reverse proxy side :
redirect
  • generally performed for Internet-related reasons (several domains pointing to the same content, pages moved across a single website, avoiding broken links, ...)
  • an HTTP 3xx status code is returned to the client (the web browser), which _can_ automatically follow the redirection (i.e. make a new request to the new URL), or wait for user action
  • implies more than a single request/response
rewrite
  • generally performed for the web application underneath (re-order / re-word parameters, ...)
  • the requested URL is translated on the server side and the corresponding content is then served to the client
  • single request/response

redirect

https://www.haproxy.com/documentation/aloha/9-5/traffic-management/lb-layer7/http-redirection/
http-request redirect location <loc> [code <code>] [<option>] [<condition>]

rewrite

	acl vhost hdr(Host) www.example.com
	acl rootRequested path /
	http-request set-path /the/new/url if vhost rootRequested
https://www.haproxy.com/documentation/aloha/9-5/traffic-management/lb-layer7/http-rewrite/

https://www.haproxy.com/documentation/aloha/9-5/traffic-management/lb-layer7/writing-conditions/
mail

[ALERT] : http frontend tries to use incompatible tcp backend as its default backend (see 'mode').

Situation

When checking the configuration, I get errors like :

[ALERT] 165/160545 (29257) : http frontend 'myFrontend' (/etc/haproxy/conf.d/myConfig.cfg:6) tries to use incompatible tcp backend 'myBackend' (/etc/haproxy/conf.d/myConfig.cfg:44) as its default backend (see 'mode').

I got this result while not using the best configuration check method. Try checking the whole HAProxy configuration before going further.

Details

Solution

Stuff below is specific to my setup (HTTP + HTTPS frontends + content switching), do NOT apply it as-is !!!

In /etc/haproxy/conf.d/myConfig.cfg, change :
frontend myFrontend
	bind 12.34.56.78:80
	mode http
	
	default_backend myBackend

frontend mySslFrontend
	bind 12.34.56.78:443
	mode tcp
	
	default_backend myBackend
into :
frontend myFrontend
	bind 12.34.56.78:80
	mode tcp
	
	default_backend myBackend

frontend mySslFrontend
	bind 12.34.56.78:443
	mode tcp
	
	default_backend myBackend
Do :
sed -ri 's/^(\s*mode\s*)http/\1tcp/g' /etc/haproxy/conf.d/myConfig.cfg
Rollback :
sed -ri 's/^(\s*mode\s*)tcp/\1http/g' /etc/haproxy/conf.d/myConfig.cfg
mail

HAProxy HTTP log format

Hover fields for description :

mars 20 11:06:49 hap01 haproxy[18799]: 12.34.56.78:18593 [20/Mar/2018:11:06:49.794] qlf-ae_https~ qlf-be-ae/ was02 47/0/3/10/60 500 518 - - ---- 97/1/0/0/0 0/0 "GET /some/resource HTTP/1.1"

Details :
HTTP status code returned to the client
this status is generally set by the server, but it might also be set by HAProxy when the server cannot be reached or when its response is blocked by HAProxy
termination_state
  • condition the session was in when the session ended
  • ---- means normal session completion after end of data transfer, both the client and the server closed with nothing left in the buffers.
  • Session state at disconnection
mail

HAProxy glossary

backend
configuration entity representing a server farm. It contains the list of servers and the load balancing strategy for this server farm
frontend
configuration entity which references one or multiple listening addresses. Its job is to :
  1. accept incoming connections
  2. apply frontend-specific processing rules to these connections (block, alter headers, ...)
  3. pass incoming connections to the backend
  4. apply backend-specific processing rules to these connections
  5. decide which server to forward the connection to according to the load balancing strategy
  6. apply the backend-specific processing rules to the response data
  7. apply the frontend-specific processing rules to the response data
  8. emit a log to report what happened in fine details
  9. in HTTP, loop back to the second step to wait for a new request, otherwise close the connection
server
host (member of a "server farm") to forward the connection to, according to the load balancing strategy
mail

How to check the configuration file ?

Method 1 : just try reloading the configuration

systemctl reload haproxy
The reload operation implies checking the configuration file, which won't reload it (hence won't affect current processes) if the config is not OK.
The reload command is handled gracefully and may not be effective immediately. If you don't want to wait to apply changes, use instead (details) :
systemctl restart haproxy

Method 2 : explicitly check a single file

There are situations where
  • "global" variables are defined in /etc/haproxy/haproxy.cfg
  • AND those settings are re-used / expected in /etc/haproxy/conf.d/*cfg (hence not re-defined)
  • AND checking a single configuration file won't read those variables
so the check will fail whereas everything is actually fine. This method _may_ not be the best...
  • $(which haproxy) -c -V -f /etc/haproxy/haproxy.cfg
  • haproxy -c -V -f custom.cfg; echo $?

Method 3 : explicitly check all configuration files

config=''; for configFile in /etc/haproxy/haproxy.cfg $(find /etc/haproxy/conf.d -type f -name "*cfg"); do config="$config -f $configFile"; done; haproxy -c -V $config
mail

HAproxy

Description

HAproxy is a solution offering high availability, load balancing, and proxying for TCP and HTTP-based applications. It is particularly suited for very high traffic web sites and powers quite a number of the world's most visited ones. Over the years it has become the de-facto standard open-source load balancer, is now shipped with most mainstream Linux distributions, and is often deployed by default in cloud platforms. (source).

HAProxy also has an enterprise edition called HAPEE.

What HAproxy is and isn't :

HAproxy is :

  • a TCP proxy : it can accept a TCP connection from a listening socket, connect to a server and attach these sockets together allowing traffic to flow in both directions
  • an HTTP reverse-proxy (called a gateway in HTTP terminology) : it presents itself as a server, receives HTTP requests over connections accepted on a listening TCP socket, and passes the requests from these connections to servers using different connections
  • an SSL terminator / initiator / offloader : SSL/TLS may be used on the connection coming from the client, on the connection going to the server, or even on both connections
  • a content-based switch : it can consider any element from the request to decide what server to pass the request or connection to. Thus it is possible to handle multiple protocols over a same port (e.g. HTTP, HTTPS, SSH)
  • a server load balancer : it can load balance TCP connections and HTTP requests. In TCP mode, load balancing decisions are taken for the whole connection. In HTTP mode, decisions are taken per request.
  • ...

HAproxy is not :

  • an explicit HTTP proxy, i.e. the proxy that browsers use to reach the internet (see Squid)
  • a caching proxy : it returns the contents received from the server as-is and will not interfere with any caching policy (see Varnish)
  • a packet-based load balancer : it will not see IP packets nor UDP datagrams, and will not perform NAT or even less DSR.
  • ...

See also Alternate / simpler solutions to HAProxy.

Usage :

It can be used in several modes :

HAProxy manuals

HAProxy keywords matrix

Utilities

Observability tips with HAProxy

http-server-close vs http-keep-alive

option http-server-close enables HTTP connection-close mode on the server side while keeping the ability to support HTTP keep-alive and pipelining on the client side.
How to enable HTTP keep alive ?

How to negate a configuration option ?

Just prefix it with no (source).