Cloud Computing‎ > ‎Load Balancing‎ > ‎HAProxy‎ > ‎

Dynamic config with LUA

Setup VM


Login with root user
$ ssh root@<ip>

Add user 'cloud'
$ sudo bash
$ adduser cloud
$ passwd cloud
Password : cloud

Add user cloud to sudo list
$ sudo echo "cloud ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers

Login with cloud user
$ ssh cloud@<ip>

Stop firewall for Centos-7
$ sudo systemctl stop firewalld
$ sudo systemctl disable firewalld
$ sudo chkconfig firewalld off
$ sudo service status firewalld

Disable SElinux 
$ sudo setenforce 0 
$ getenforce

Compiling HAProxy with Lua


Install LUA 5.3.1

HAProxy 1.6\1.7 requires Lua 5.3. Lua 5.3 offers some features which make easy the
integration. Lua 5.3 is young, and some distros do not distribute it. Luckily,
Lua is a great product because it does not require exotic dependencies, and its
build process is really easy.

Install Dependencies:
 - Install gcc
   $ sudo yum install -y gcc gcc-c++ kernel-devel 

The compilation process for linux is easy:

 - download the source tarball

 - untar it
   tar xf lua-5.3.1.tar.gz

 - enter the directory
   cd lua-5.3.1

 - build the library for linux
   If you're running Linux and get compilation errors, make sure you have installed the readline development package (which is probably named libreadline-dev or readline-devel).

   sudo yum install -y readline-devel
   make linux

 - install it:
   sudo make INSTALL_TOP=/usr install [This is to overwrite system default lua 5.1.0 to 5.3.0]
   sudo make INSTALL_TOP=/opt/lua-5.3.1 install [This is used by HAProxy from /opt location]



The LUA-cjson is a library required for any json parsing in LUA code.

$ wget
$ tar -xzvf lua-cjson-2.1.0.tar.gz

$ cd lua-cjson-2.1.0
vi Makefile
LUA_VERSION =       5.3
PREFIX =             /usr

$ vi lua-cjson-2.1.0-1.rockspec
dependencies = {
    "lua >= 5.3"

$ vi lua-cjson.spec

%define luaver 5.3

#sudo make install
Console logs -
$ cp //usr/lib/lua/5.3
$ chmod 755 //usr/lib/lua/5.3/

$ sudo cp /usr/lib/lua/5.3/ /opt/lua-5.3.1/lib/
$ sudo cp /usr/lib/lua/5.3/ /opt/lua-5.3.1/lib/lua/5.3/

Install HAProxy 1.7\1.6 with LUA


HAProxy builds with your favourite options, plus the following options for
embedding the Lua script language:

 - download the source tarball

 - untar it
   tar -xzvf haproxy-ss-20160518

 - enter the directory
   cd haproxy-ss-20160518

 - build HAProxy:
   To fix openssl errors
   sudo yum install -y openssl-devel
   make TARGET=linux \
        USE_DL=1 \
        USE_LUA=1 \
        LUA_LIB=/opt/lua-5.3.1/lib \

   [ backup - if wanna install in /usr]
   make TARGET=linux \
        USE_DL=1 \
        USE_LUA=1 \
        LUA_LIB=/usr/lib/lua/5.3/ \


 - install it:
   sudo make PREFIX=/opt/haproxy-1.7 install

   [ backup - if wanna install in /usr]
   sudo make PREFIX=/usr install

Configure HAProxy


 - copy binary file to sbin
   sudo cp /opt/haproxy-1.7/sbin/haproxy /usr/sbin/

 - copy init file
   sudo cp /home/cloud/haproxy/haproxy-1.7-dev3/examples/haproxy.init /etc/init.d/haproxy
   sudo chmod 755 /etc/init.d/haproxy

 - Create these directories and the statistics file for HAProxy to record in.

   sudo mkdir -p /etc/haproxy
   sudo mkdir -p /run/haproxy
   sudo mkdir -p /var/lib/haproxy
   sudo touch /var/lib/haproxy/stats

 - Then add a new user for HAProxy.
   sudo useradd -r haproxy

 - After the installation you can double check the installed version number with the following
    $ sudo haproxy -v
      HA-Proxy version 1.7-dev3-27b639d 2016/05/17
      Copyright 2000-2016 Willy Tarreau <>

 - Configure the load balancer
   sudo vi /etc/haproxy/haproxy.cfg
   Add the config

HAProxy Script

$ cat /etc/haproxy/haproxy.cfg

# Example configuration for a possible web application.  See the
# full configuration options online.

# Global settings
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:
    # 1) configure syslog to accept network log events.  This is done
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in
    #    /etc/sysconfig/syslog
    # 2) configure local2 events to go to the /var/log/haproxy.log
    #   file. A line like the following can be added to
    #   /etc/sysconfig/syslog
    #    local2.*                       /var/log/haproxy.log
    log local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/
    maxconn     4000
    user        haproxy
    group       haproxy

    lua-load /usr/sbin/lua-choose-backend.lua

    # turn on stats unix socket
    stats socket /var/run/haproxy.sock mode 600 level admin
    stats timeout 2s
    log local0

# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

# main frontend which proxys to the backends
frontend  main
    bind *:7000
    acl url_static       path_beg       -i /static /images /javascript /stylesheets
    acl url_static       path_end       -i .jpg .gif .png .css .js

    use_backend static          if url_static
    default_backend             backend1

frontend http-in
    mode http

    log-format %ci:%cp\ [%t]\ %ft\ %b/%s\ %Tq/%Tw/%Tc/%Tr/%Tt\ %ST\ %B\ %CC\ %CS\ %tsc\ %ac/%fc/%bc/%sc/%rc\ %sq/%bq\ %hr\ %hs\ {%[ssl_c_verify],%{+Q}[ssl_c_s_dn],%{+Q}[ssl_c_i_dn]}\ %{+Q}r

    bind *:443 ssl crt /etc/haproxy/server.pem ca-file /etc/haproxy/ca.crt verify required

    use_backend %[lua.choose_backend]
    #default_backend backend1
    reqadd X-Forwarded-Proto:\ https if { ssl_fc }
    option forwardfor

# With HAProxy Enterprise HAPEE, this is for dynamic disk write for map updates
#       update id url delay 30s timeout 5s retries 3 map

frontend ssl-in
    mode tcp
    bind *:8443 ssl crt /etc/haproxy/server.pem ca-file /etc/haproxy/ca.crt verify required
    default_backend backendssh
    option tcplog
    tcp-request inspect-delay 5s
    tcp-request content accept if HTTP

listen stats
   bind *:8181
   stats enable
   stats uri /
   stats realm Haproxy\ Statistics
   stats auth cloud:cloud

# static backend for serving up images, stylesheets and such
backend static
    balance     roundrobin
    server      static check

# round robin balancing between the various backends
backend backend1
    balance     roundrobin
    server app1 check
    server app2 check

backend backend2
    balance     roundrobin
    server app3 check
    server app4 check

backend backendssh
    mode tcp
    balance     roundrobin
    server app1 check
    server app2 check
    server app3 check
    server app4 check
    timeout server 2h

LUA Script


-- Cloud map

cloudmetadata ="/home/cloud/", Map.str);

clouddynamicdata ="/home/cloud/", Map.str);

local function split( inSplitPattern, outResults )

   if not outResults then
      outResults = {}
   local theStart = 1
   local theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
   while theSplitStart do
      table.insert( outResults, string.sub( self, theStart, theSplitStart-1 ) )
      theStart = theSplitEnd + 1
      theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
   table.insert( outResults, string.sub( self, theStart ) )
   return outResults

local function find_backend(cn)


        --local json = require('cjson')

        core.log(, cn)
        -- backend1

        local clouddynamic = clouddynamicdata:lookup(cn);
        if(clouddynamic == nil) then
                core.log(, "clouddynamic nil")
                core.log(, clouddynamic)
                return clouddynamic

        local metadata = cloudmetadata:lookup(cn);

        if(metadata == nil) then
                core.log(, "metadata nil")

        core.log(, metadata)
        -- 10

        core.set_map("/home/cloud/", cn, 14) 
-- this is in-memory write won't get flushed to disk
-- to flush to disk, run external service which would periodically poll /home/cloud/ and write to disk map. 

        return metadata

function choose_backend(txn)

        local arg1 = txn.f:ssl_c_s_dn("CN")
        backend = find_backend (arg1)

        return backend

core.register_fetches("choose_backend", choose_backend)

Setup logging in HAproxy


Step 1: In Global Section of haproxy.cfg put the value log local0 .Like given below

        log   local0
Step 2: Create new haproxy configuration file in /etc/rsyslog.d . Here we are keeping the log in localhost or in other words we should say HAproxy server

local0.=info -/var/log/haproxy.log defines the http log will be saved in haproxy.log
local0.notice -/var/log/haproxy-status.log defines the Server status like start,stop,restart,down,up etc. will be saved in haproxy-status.log
UDPServerRun 514 means opening UDP port no. 514 to listen haproxy messages
sudo vi /etc/rsyslog.d/haproxy.conf

$ModLoad imudp
$UDPServerRun 514 
$template Haproxy,"%msg%\n"
local0.=info -/var/log/haproxy.log;Haproxy
local0.notice -/var/log/haproxy-status.log;Haproxy
### keep logs in localhost ##
local0.* ~ 

Step 3: Now restart the HAproxy service

$ sudo service rsyslog restart
$ sudo service https restart
After restarting the haproxy service two logs will be created itself i.e haproxy.log and haproxy-status.log

Install netcat (nc)
$ sudo yum install -y nc

$ sudo tail -f /var/log/haproxy.log

Start HAProxy


  - Copy SSL files


   $ cat
   backend1 10
   backend2 2

  - Start
    sudo service haproxy start

Dynamic map


1. Turn on stat socket
   $ sudo vi /etc/haproxy/haproxy.cfg
   $ stats socket /var/lib/haproxy.sock mode 600 level admin

2. Install socat
   $ sudo yum install socat

   $ echo "show map /home/cloud/" | sudo socat /var/run/haproxy.sock stdio
   0x16cf160 backend1 10
   0x16cf300 backend2 2

   $ echo "set map /home/cloud/ backend2 14" | sudo socat /var/run/haproxy.sock stdio
   $ echo "show map /home/cloud/" | sudo socat /var/run/haproxy.sock stdio
   0x8de070 backend1 10
   0x8de0a0 backend2 14

   $ cat /home/cloud/
   backend1 10
   backend2 2   

   The in-memory state of /home/cloud/ is dynamically set by set map cmd or set_map LUA API
   The on-disk /home/cloud/ remains un-altered, means dynamic changes are not persistent and would vanish on HAProxy reload.
   To make the dynamic changes persistence, run a separate external service to also write the dynamic changes to disk map /home/cloud/
   This would ensure changes to persist as well as keep the disk write load and latency limited to external service and not to HAProxy.