Debian: HAProxy and Keepalived (LoadBalancer)

HAProxy is a free and open source software that provides a high availability load balancer and proxy server for TCP and HTTP-based applications that spreads requests across multiple servers. It is written in C and has a reputation for being fast and efficient.

Keepalived main goal is to provide simple and robust facilities for loadbalancing and high-availability to Linux system and Linux based infrastructures. Loadbalancing framework relies on well-known and widely used Linux Virtual Server (IPVS) kernel module providing Layer4 loadbalancing. Keepalived implements a set of checkers to dynamically and adaptively maintain and manage loadbalanced server pool according their health. On the other hand high-availability is achieved by the Virtual Router Redundancy Protocol (VRRP). VRRP is a fundamental brick for router failover. In addition, Keepalived implements a set of hooks to the VRRP finite state machine providing low-level and high-speed protocol interactions. In order to offer fastest network failure detection, Keepalived implements the Bidirectional Forwarding Detection (BFD) protocol. VRRP state transition can take into account BFD hints to drive fast state transition. Keepalived frameworks can be used independently or all together to provide resilient infrastructures.

Step 1: Install Packages

The following packages will need to be installed on both nodes that are to act as a loadbalancer:

# apt install haproxy keepalived

Step 2: Configure Keepalived

Configure keepalived for the “MASTER” and “BACKUP” node, each containing the following values:

  • Define the state as MASTER
  • Define the interface
  • Define the Virtual Router ID
  • Define priority (higher will win)
  • Define authentication
  • Define Virtual IP Address

Change settings in /etc/keepalived/keepalived.conf on the “MASTER” node

! Configuration File for keepalived

global_defs {
   notification_email {
     admin@mydomain.org
   }
   notification_email_from lb-keepalived@mydomain.org
   smtp_server <smtp-server-ip>
   smtp_connect_timeout 30
   router_id lb-01
}

vrrp_instance VI_1_IPv4 {
    state MASTER
    interface ens224
    smtp_alert
    virtual_router_id 51
    priority 200

    unicast_src_ip <IP PRIMARY IPv4 LB>
    unicast_peer {
       <IP SECONDARY IPv4 LB>
    }
    authentication {
        auth_type PASS
        auth_pass dWau6GCHA2LvxRD6Rjth3pzX
   }

   advert_int 1
   virtual_ipaddress {
        <virtual-ip-address>
   }

}

Change settings in /etc/keepalived/keepalived.conf on the “BACKUP” node

! Configuration File for keepalived

global_defs {
   notification_email {
     admin@mydomain.org
   }
   notification_email_from lb-keepalived@mydomain.org
   smtp_server <smtp-server-ip>
   smtp_connect_timeout 30
   router_id lb-01
}

vrrp_instance VI_1_IPv4 {
    state BACKUP
    interface ens224
    smtp_alert
    virtual_router_id 51
    priority 100

   unicast_src_ip <IP PRIMARY IPv4 LB>
   unicast_peer {
       <IP SECONDARY IPv4 LB>
    }

    authentication {
        auth_type PASS
        auth_pass dWau6GCHA2LvxRD6Rjth3pzX
   }

   advert_int 1
   virtual_ipaddress {
        <virtual-ip-address>
   }

}

On both nodes enable and start the keepalived service

# systemctl enable keepalived
# systemctl restart keepalived

On the “MASTER” node you should see the virtual-ip address avaialble

# ip addr list

Step 3: Configure HAProxy

Change settings in /etc/haproxy/haproxy.conf on both “MASTER” and “BACKUP” nodes

  • Define the <internal-ip-address> for communication for statistics and information
  • Define the various frontend and backend services needed
global
    log /dev/log    local0
    log /dev/log    local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

    # Default SSL material locations
    ca-base /etc/ssl/certs
    crt-base /etc/ssl/private
    tune.ssl.default-dh-param 2048

    # 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 ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

listen stats
    bind <internal-ip>:8181
    mode http
    maxconn 5
    timeout client      100s
    timeout server      100s
    timeout connect     100s
    timeout queue       100s
    stats enable
    stats hide-version
    stats refresh 30s
    stats show-node
    stats auth admin:VbWWNsQD4QLTsMejWaGPjms5
    stats uri /haproxy?stats

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

################
# WEB : 80
################
frontend vs_web_80 
     bind *:80
     mode http
     default_backend pool_web_80

backend pool_web_80
     balance roundrobin
     option forwardfor
     option http-server-close
     http-request set-header X-Forwarded-Port %[dst_port]
     http-request add-header X-Forwarded-Proto https if { ssl_fc }
     server web1 www-01.internal.mydomain.org:80 check
     server web2 www-02.internal.mydomain.org:80 check

################
# WEB : 443
################
frontend vs_web_443
      bind *:443 ssl crt /etc/haproxy/ssl/mydomain.org-chain.pem
      mode http
      option tcplog
      default_backend pool_web_443

backend pool_web_443
      balance roundrobin
      option forwardfor
      option http-server-close
      http-request set-header X-Forwarded-Port %[dst_port]
      http-request add-header X-Forwarded-Proto https if { ssl_fc }
      server web1 www-01.internal.mydomain.org:443 check maxconn 20 ssl verify none
      server web2 www-02.internal.mydomain.org:443 check maxconn 20 ssl verify none

Before starting the service, you can check the configuration on each node

# haproxyctl configcheck
Configuration file is valid

On both nodes enable and start the haproxy service

# systemctl enable haproxy
# systemctl restart haproxy

Status can be checked using the CLI:

haproxyctl show backend
stats BACKEND UP 0
pool_web_80 BACKEND UP 2
pool_web_443 BACKEND UP 2
pool_ftp_21 BACKEND UP 1

haproxyctl show health
# pxname svname status weight
stats FRONTEND OPEN
stats BACKEND UP 0

vs_web_80 FRONTEND OPEN
pool_web_80 web1 UP 1
pool_web_80 web2 UP 1
pool_web_80 BACKEND UP 2

vs_web_443 FRONTEND OPEN
pool_web_443 web1 UP 1
pool_web_443 web2 UP 1
pool_web_443 BACKEND UP 2

vs_ftp_21 FRONTEND OPEN
pool_ftp_21 ftp1 DOWN 1
pool_ftp_21 ftp2 UP 1
pool_ftp_21 BACKEND UP 1

Or visit the haproxy service defined in the configuration file e.g. http://proxy-01.mydomain.org;8181/haproxy?stats