How to use variable to choose HAProxy backend

Define and use variable to dynamically choose HAProxy backend depending on the URL parameter, HTTP header field and a cookie value.

HAProxy version.

$ haproxy -v
HA-Proxy version 1.7.5-2 2017/05/17
Copyright 2000-2017 Willy Tarreau <[email protected]>

Default HAProxy configuration.

global
	log /dev/log	local0
	log /dev/log	local1 notice
	chroot /var/lib/haproxy
	stats socket /run/haproxy/admin.sock mode 660 level admin
	stats timeout 30s
	user haproxy
	group haproxy
	daemon

	# Default SSL material locations
	ca-base /etc/ssl/certs
	crt-base /etc/ssl/private

	# Default ciphers to use on SSL-enabled listening sockets.
	# For more information, see ciphers(1SSL). This list is from:
	#  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
	# An alternative list with additional directives can be obtained from
	#  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
	ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
	ssl-default-bind-options no-sslv3

defaults
	log	global
	mode	http
	option	httplog
	option	dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
	errorfile 400 /etc/haproxy/errors/400.http
	errorfile 403 /etc/haproxy/errors/403.http
	errorfile 408 /etc/haproxy/errors/408.http
	errorfile 500 /etc/haproxy/errors/500.http
	errorfile 502 /etc/haproxy/errors/502.http
	errorfile 503 /etc/haproxy/errors/503.http
	errorfile 504 /etc/haproxy/errors/504.http

Choose backend using URL parameter

Sample frontend and backends using the backend_color URL parameter.

rontend development-frontend
  bind :80
  #bind :443 ssl crt /etc/ssl/cert/

  option httplog
  log /dev/log local0 debug

  option forwardfor except 127.0.0.1
  option forwardfor header X-Real-IP

  #redirect scheme https code 301 if !{ ssl_fc }

  acl is-backend-color-set-properly urlp_reg(backend_color) ^(red|green|blue)$
  http-request set-var(req.backend_color) urlp(backend_color) if is-backend-color-set-properly

  use_backend backend-%[var(req.backend_color)] if is-backend-color-set-properly  
  use_backend backend-default


backend backend-default
  server default 10.66.91.125:80

backend backend-red
  server default-red 10.66.91.52:80

backend backend-green
  server default-green 10.66.91.53:80

backend backend-blue
  server default-blue 10.66.91.50:80

Sample log output for regular query (default backend).

$ curl http://10.66.91.165/
Jan 20 20:08:32 dev haproxy[4174]: 10.66.91.165:46224 [20/Jan/2018:20:08:32.914] development-frontend backend-default/default 0/0/0/5/5 200 9386 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"

Sample log output for regular query with backend_color defined as red (red backend).

$ curl http://10.66.91.165/?backend_color=red 
Jan 20 20:08:43 dev haproxy[4174]: 10.66.91.165:46232 [20/Jan/2018:20:08:43.266] development-frontend backend-red/default-red 0/0/0/0/0 301 805 - - ---- 1/1/0/1/0 0/0 "GET /?backend_color=red HTTP/1.1"

Sample log output for regular query with backend_color defined as green (green backend).

$ curl http://10.66.91.165/?backend_color=green
Jan 20 20:08:48 dev haproxy[4174]: 10.66.91.165:46236 [20/Jan/2018:20:08:48.531] development-frontend backend-green/default-green 0/0/0/1/1 200 29158 - - ---- 1/1/0/1/0 0/0 "GET /?backend_color=green HTTP/1.1"

Sample log output for regular query with backend_color defined as blue (blue backend).

$ curl http://10.66.91.165/?backend_color=blue
Jan 20 20:08:55 dev haproxy[4174]: 10.66.91.165:46240 [20/Jan/2018:20:08:55.108] development-frontend backend-blue/default-blue 0/0/0/0/0 200 11174 - - ---- 1/1/0/1/0 0/0 "GET /?backend_color=blue HTTP/1.1"

Choose backend using HTTP header field

Sample frontend and backends using the backend_color URL parameter.

rontend development-frontend
  bind :80
  #bind :443 ssl crt /etc/ssl/cert/

  option httplog
  log /dev/log local0 debug

  option forwardfor except 127.0.0.1
  option forwardfor header X-Real-IP

  #redirect scheme https code 301 if !{ ssl_fc }

  acl is-backend-color-set-properly hdr_reg(x-backend-color) ^(red|green|blue)$
  http-request set-var(req.backend_color) hdr(x-backend-color) if is-backend-color-set-properly

  use_backend backend-%[var(req.backend_color)] if is-backend-color-set-properly  
  use_backend backend-default


backend backend-default
  server default 10.66.91.125:80

backend backend-red
  server default-red 10.66.91.52:80

backend backend-green
  server default-green 10.66.91.53:80

backend backend-blue
  server default-blue 10.66.91.50:80

Sample log output for regular query (default backend).

$ curl http://10.66.91.165/


Sample log output for regular query with backend_color defined as red (red backend).

$ curl http://10.66.91.165/ --header "x-backend-color: red"
Jan 20 20:48:00 dev haproxy[4279]: 10.66.91.165:46692 [20/Jan/2018:20:48:00.781] development-frontend backend-red/default-red 0/0/0/0/0 301 805 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"

Sample log output for regular query with backend_color defined as green (green backend).

$ curl http://10.66.91.165/ --header "x-backend-color: green"
Jan 20 20:49:14 dev haproxy[4279]: 10.66.91.165:46718 [20/Jan/2018:20:49:14.269] development-frontend backend-green/default-green 0/0/0/0/0 200 29158 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"

Sample log output for regular query with backend_color defined as blue (blue backend).

$ curl http://10.66.91.165/ --header "x-backend-color: blue"
Jan 20 20:49:17 dev haproxy[4279]: 10.66.91.165:46722 [20/Jan/2018:20:49:17.761] development-frontend backend-blue/default-blue 0/0/0/0/0 200 11174 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"

Choose backend using URL parameter and a cookie for persistence

Sample frontend and backends using the backend_color URL parameter and a cookie for persistence.

frontend development-frontend
  bind :80
  #bind :443 ssl crt /etc/ssl/cert/

  option httplog
  log /dev/log local0 debug

  option forwardfor except 127.0.0.1
  option forwardfor header X-Real-IP

  #redirect scheme https code 301 if !{ ssl_fc }

  acl is-backend-color-set-to-clear urlp_reg(backend_color) "^clear\$"
  #reqidel ^Cookie:.*backend_color= if is-backend-color-set-to-clear

  acl is-backend-color-set-properly urlp_reg(backend_color) "^(red|green|blue)\$"
  http-request set-var(txn.backend_color) urlp(backend_color) if is-backend-color-set-properly 

  acl is-backend-color-cookie-set-properly cook_reg(backend_color) "^(red|green|blue)\$"
  http-request set-var(txn.backend_color) cook(backend_color) if !is-backend-color-set-properly is-backend-color-cookie-set-properly 
  
  use_backend backend-%[var(txn.backend_color)] if is-backend-color-set-properly or is-backend-color-cookie-set-properly !is-backend-color-set-to-clear
  use_backend backend-default

backend backend-default
  reqidel ^Cookie:.*backend_color=
  server default 10.66.91.125:80

backend backend-red
  http-response add-header Set-Cookie backend_color=%[var(txn.backend_color)];\ path=/
  server default 10.66.91.52:80

backend backend-green
  http-response add-header Set-Cookie backend_color=%[var(txn.backend_color)];\ path=/
  server default-green 10.66.91.53:80

backend backend-blue
  http-response add-header Set-Cookie backend_color=%[var(txn.backend_color)];\ path=/
  server default-blue 10.66.91.50:80

Sample log output for regular query (default backend).

$ curl http://10.66.91.165/
Jan 20 23:20:04 dev haproxy[5341]: 10.66.91.165:48958 [20/Jan/2018:23:20:04.827] development-frontend backend-default/default 0/0/0/7/8 200 9386 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"

Sample log output for regular query with backend_color defined as red (cookie set to red backend).

$ curl --silent --output /dev/null --cookie-jar - http://10.66.91.165/?backend_color=red
# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

10.66.91.165	FALSE	/	FALSE	0	backend_color	red
Jan 20 23:25:18 dev haproxy[5620]: 10.66.91.165:49456 [20/Jan/2018:23:25:18.074] development-frontend backend-red/default 0/0/0/1/1 301 805 - - ---- 1/1/0/1/0 0/0 "GET /?backend_color=red HTTP/1.1"

Sample log output for regular query with backend_color switched from red to green (cookie set to green backend).

$ curl --silent --output /dev/null --cookie "backend_color: red" --cookie-jar - http://10.66.91.165/?backend_color=green
# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

10.66.91.165	FALSE	/	FALSE	0	backend_color	green
Jan 20 23:26:32 dev haproxy[5620]: 10.66.91.165:49470 [20/Jan/2018:23:26:32.552] development-frontend backend-green/default-green 0/0/0/0/0 200 29158 - - ---- 1/1/0/1/0 0/0 "GET /?backend_color=green HTTP/1.1"

Sample log output for regular query with backend_color switched from blue to none/default (default backend).

$ curl --silent --output /dev/null --cookie "backend_color=green" --cookie-jar - http://10.66.91.165/?backend_color=clear -v
*   Trying 10.66.91.165...
* TCP_NODELAY set
* Connected to 10.66.91.165 (10.66.91.165) port 80 (#0)
> GET /?backend_color=clear HTTP/1.1
> Host: 10.66.91.165
> User-Agent: curl/7.52.1
> Accept: */*
> Cookie: backend_color=green
> 
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.10.3 (Ubuntu)
< Date: Sat, 20 Jan 2018 23:21:17 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Location: p/
< X-Clacks-Overhead: GNU Terry Pratchett
< Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
< X-Frame-Options: SAMEORIGIN
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< X-Download-Options: noopen
< X-Permitted-Cross-Domain-Policies: none
< 
{ [320 bytes data]
* Curl_http_done: called premature == 0
* Connection #0 to host 10.66.91.52 left intact
Jan 20 23:29:47 dev haproxy[5675]: 10.66.91.165:49538 [20/Jan/2018:23:29:47.966] development-frontend backend-default/default 0/0/0/5/6 200 9386 - - ---- 1/1/0/1/0 0/0 "GET /?backend_color=clear HTTP/1.1"

About Milosz Galazka

Milosz is a Linux Foundation Certified Engineer working for a successful Polish company as a system administrator and a long time supporter of Free Software Foundation and Debian operating system.