Configuration of HAProxy


Introduction

Welcome to part three in a series of guides on HAProxy. In the first two installments in the series, you were introduced to HAProxy, its terminology, a few ways in which it can be used and then finally, how to install it using either your package manager or from source. If you are not familiar with HAProxy, its uses or how to install it, please take this time to review the first two guides before jumping into this one.

In this guide, you will be shown how to configure HAProxy in a larger organization that is utilizing multiple backend application servers that are serving content to users.

By the end of this guide, you should be comfortable implementing this type of configuration in your environment following basic HAProxy configuration steps.


Setup

Before you dive into the heart of the configuration, you need to understand the big picture. In this scenario, you are going to be putting together an HAProxy configuration that will handle multiple backend servers that are hosting applications for a GIS company. 

The following graphic should give you an idea of the layout. Once you have a grasp on the setup, move forward where we will start building the configuration file, section by section.

user_55565_589853fa04158.png_800.jpg











Global

Up first is the global defaults which consists of setting the max number of connections allowed as well as tuning the cipher suites that HAProxy will use. All of these options are documented in the HAProxy documentation but I want to note that I have simply used Mozilla’s SSL Generator to generate the SSL settings below. You will need to ensure that you choose the appropriate settings for your setup.


daemon 
maxconn 4096
tune.ssl.default-dh-param 2048
ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
ssl-default-server-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets


Defaults

Next up are the defaults where you can tweak your timeouts, etc. Once again, I want to point out a few key options here. The redispatch option enables the rerouting of a user’s session in the event their connection fails. This would prevent the customers from getting errors on their end unexpectedly. 

The next one to take note of is forwardfor. This option enables us to insert a X-Forwarded-For header on responses. This header will be setup later in the frontend configuration and this option only enables us to use it later. 

The last one to note enables HAProxy to close connections from the server side that are no longer in use. The option is called http-server-close and is helpful since HAProxy will hang on to connections even after they are no longer being used, this allows you to kill those connections and free up resources.


mode http 
timeout connect 25000ms
timeout client 60000ms
timeout server 60000ms
timeout queue 60000ms
timeout http-request 15000ms
timeout http-keep-alive 15000ms
option redispatch
option forwardfor
option http-server-close


Frontend

Next up, the frontends. As you can see from the below example, HAProxy is fairly straight forward with what each setting does but nevertheless, lets break down what was done.

  1. Defined the port that is listening for traffic. In this example, we have setup both HTTP(80) & HTTPS(443).
  2. Setup the X-Forward headers to always send our DNS alias back out to users. In this example, we are using example.com.
  3. Because we do not want users on HTTP but we also do not want them to worry about specifying HTTPS in their url every time, we have setup a redirect on HTTP(80) so that anytime they access HTTP(80), they are automatically redirected to HTTPS(443).
  4. Enabled HSTS so that a user’s browser will not attempt to downgrade their HTTPS connect to HTTP.
  5. Defined ACL rules to direct traffic to the correct backend application pools. Below is a breakdown of these rules.
  6. Define a default backend that traffic is sent to if it does not meet any of the ACL rules we have defined.

As we mentioned above, lets break down one of the ACL rules in the example below. Because all of the rules are using the same syntax, we only need to break one down to understand all of them. Let’s first look at the syntax for an ACL.

Syntax:

user_55565_589855705b35e.png




Example:

user_55565_5898557e18732.png





If we compare they syntax to our rule using the simple color breakdown below, you should be able to see how they are built.

  • Red: Defines the start of a new rule
  • Purple: Defines a name of the new rule
  • Green: Defines the portion of request or response where this ACL applies. We are using path_beg which looks for a prefix match in response and requests.
  • Orange: Completes the criterion, to make it more accurate on the place and way to apply the ACL. We are using -i which simply ignores case during matching.
  • Blue: Pattern that will be searched for on requests or responses. The example is looking for the url that will match the pattern of https://example.com/image with /image being the pattern it matches.

A rule can be as simple as looking for a pattern in the request or response up to whatever you need it to do. The ability to document every aspect of HAProxy rules is well outside the scope of this guide. I would highly recommend you read their documentation which is extremely thorough in what it is capable of.


frontend http-in
bind 10.0.1.50:80
rspadd X-Forwarded-Host:\ http:\\\example.com
redirect scheme https code 301 if !{ ssl_fc }

frontend https-in
bind 10.0.1.50:443 ssl crt /etc/ssl/bundle.pem
rspadd X-Forwarded-Host:\ https:\\\\example.com
rspadd Strict-Transport-Security:\ max-age=31536000

acl url_image path_beg -i /image/
use_backend image-backend if url_image

acl url_map path_beg -i /map/
use_backend map-backend if url_map

acl url_geocode path_beg -i /geocode/
use_backend geocode-backend if url_geocode

acl url_stream path_beg -i /stream/
use_backend stream-backend if url_stream

default_backend image-backend

Backend

Now that we have configured our frontend, we need somewhere to send our requests and that is what we have setup in the backend. The first step in configuring a backend is to define it with the following syntax.


backend <name>

In this example, we have defined four backends which will contain their respective application servers. Once you have defined your backend, the next step is to define the actual servers within, which is done with the following syntax.


server <name> <IP or FQDN>:<port> <options>


Once again, we have populated each backend with their respective servers. We have assigned each server a unique name so that we can differentiate between them as well as defined their IP and port they are listening on.

The next step in this process is to determine what options you will need or want with your servers. In the example, we have chosen to go with a few basic ones which are described below.

The check option allows HAProxy to query the state of a server. A server can have one of four states which are UP, UP-transitionally DOWN (going down), DOWN-transitionally UP (coming up) and DOWN.

The ssl option enables HAProxy to communication with a backend server using a secure connection. When this is enabled, it will also secure the health check traffic.

The backup option is used to specify a server that you only wish to use once all other servers in the backend are down. This sort of behavior is typical when you want all requests to go to one server at all times unless there is a failure of some nature.

Lastly, the verify option is used to verify the certificates from your application servers. You have the option of using verify none or verify all. In this example, we are using verify none because we are using self-signed certificates on the application servers.


backend image-backend 
server image01 10.0.5.10:443 check ssl verify none
server image02 10.0.5.11:443 check ssl verify none
server image03 10.0.5.12:443 check ssl verify none

backend map-backend
server map01 10.0.5.13:6443 check ssl verify none
server map02 10.0.5.14:6443 check ssl verify none
server map03 10.0.5.15:6443 check backup ssl verify none

backend geocode-backend
server geocode01 10.0.5.16:6080 check
server geocode02 10.0.5.17:6080 check backup

backend stream-backend
server stream01 10.0.5.18:6443 check ssl verify none
server stream02 10.0.5.19:6443 check backup ssl verify none
server stream03 10.0.5.20:6443 check backup ssl verify none
server stream04 10.0.5.21:6443 check backup ssl verify none

Complete
global
daemon
maxconn 4096
tune.ssl.default-dh-param 2048
ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM- SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
ssl-default-server-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM- SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets

defaults
mode http
timeout connect 25000ms
timeout client 60000ms
timeout server 60000ms
timeout queue 60000ms
timeout http-request 15000ms
timeout http-keep-alive 15000ms
option redispatch
option forwardfor
option http-server-close

frontend http-in
bind 10.0.1.50:80
rspadd X-Forwarded-Host:\ http:\\\example.com
redirect scheme https code 301 if !{ ssl_fc }

frontend https-in
bind 10.0.1.50:443 ssl crt /etc/ssl/bundle.pem
rspadd X-Forwarded-Host:\ https:\\\\example.com
rspadd Strict-Transport-Security:\ max-age=31536000

acl url_image path_beg -i /image/
use_backend image-backend if url_image

acl url_map path_beg -i /map/
use_backend map-backend if url_map

acl url_geocode path_beg -i /geocode/
use_backend geocode-backend if url_geocode

acl url_stream path_beg -i /stream/
use_backend stream-backend if url_stream

default_backend image-backend

backend image-backend
server image01 10.0.5.10:443 check ssl verify none
server image02 10.0.5.11:443 check ssl verify none
server image03 10.0.5.12:443 check ssl verify none

backend map-backend
server map01 10.0.5.13:6443 check ssl verify none
server map02 10.0.5.14:6443 check ssl verify none
server map03 10.0.5.15:6443 check backup ssl verify none

backend geocode-backend
server geocode01 10.0.5.16:6080 check verify none
server geocode02 10.0.5.17:6080 check verify none backup

backend stream-backend
server stream01 10.0.5.18:6443 check ssl verify none
server stream02 10.0.5.19:6443 check backup ssl verify none
server stream03 10.0.5.20:6443 check backup ssl verify none
server stream04 10.0.5.21:6443 check backup ssl verify none


Conclusion

As you should now see, the process for building a HAProxy configuration is fairly straight forward. With that said, you should keep in mind that HAProxy can be used for just about any scenario and as such, its configuration options are endless.


Additional Resources

The following resources may help with additional understanding of the ways in which HAProxy can be configured and used.

HAProxy Documentation - http://www.haproxy.org/#docs

Mozilla SSL Generator - https://mozilla.github.io/server-side-tls/ssl-config-generator/

HSTS - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security



  • post-author-pic
    Johnny J
    02-06-2017

     @mhatcher: This looks really great! Great job!

  • post-author-pic
    David C
    02-06-2017

    Good stuff Michael!

  • post-author-pic
    Aj N
    10-25-2017

    Nice tutorial Mickael  @mhatcher  , how can I get inf. about the balancing what server gets how many connections at any time?
    I would like to collect  this information regularly to be shown in another program

  • post-author-pic
    Alvaro Camilo A
    03-02-2018

    Really greate Job!! it help's me to resolve a configuration problem that I had on my work to configure ssl termination and it will be perfect for me.

  • post-author-pic
    Arnaud C
    04-04-2018

     @ajnouri  you can place a "listen stats" in haproxy with a user and password to have a webinterface statistics for haproxy (look at the doc ). and the following command can help "hatop -s /run/haproxy/admin.socks" 

Looking For Team Training?

Learn More