Skip to main content
Skip table of contents

Load balancing with HAProxy

HAProxy is an open-source software capable of processing Layer 4 and Layer 7 traffic. It supports high availability, load-balancing, and proxying traffic to one or more backend servers.

Installation

Requirements

HAProxy can be installed and run on any platform that HAProxy supports. In this article, we focus on the installation of HAProxy on Alma Linux 9 and RHEL.

If possible, install HAProxy on a dedicated server for security and performance reasons. However, you can also install it on the same server where a censhare Server is running. In this case, make sure that the following ports are not in use so that HAProxy can bind to them:

  • 80  - Plain HTTP. It is redirected to port 443.

  • 443  - Default HTTPs port.

  • 30546  - By default, censhare RMI uses port 30546. Therefore, when running HAProxy on a dedicated server, we recommend using port 30546 here as well. However, when running HAProxy on the same machine as a censhare Server, for example, the Master server, use another port such as 30545. Also, ensure that your hosts.xml contains the correct port defined to use with HAProxy.

  • 8080  - HAProxy statistics.

How to verify that the ports are available:

CODE
ss -tulnp | egrep '80|443|30546|8080'


Installation command

To install HAProxy on Alma Linux 9 7 and RHEL 7 and later versions, install the package from the distribution repository. Run the following command:

CODE
yum install haproxy

Configuration

Note: For a complete guide on how to configure HAProxy, see the Configuration Manual for the Community Edition.

Find an example of a configuration file for HAProxy that you can use for load-balancing and high-availability for censhare. The configuration file defines an environment with two censhare Servers, one of them as the Master server.

First, identify the appropriate custom values for your environment for the following items. Then adapt the example configuration file:

  1. If the application has a custom context path that is different from the default  /censhare5/client, check all entries of  /censhare5/client in the configuration file. Replace the entries with the appropriate context path. For example, if the base URL is:

    CODE
    https://customer.example.com/censhareapp 

    The custom context path is censhareapp. Then, set the http-request redirect line in the configuration file:

    CODE
    http-request redirect code 301 location https://%[hdr(host)]/censhareapp
  2. Upload a PEM-formatted SSL certificate file to the server. This file should contain both the private key and the certificate chain bundle. This means: When a certificate is signed by an intermediate certificate authority (CA), also include the certificate of the intermediate CA in addition to the actual certificate.

    Example of a PEM-format certificate:

    CODE
    -----BEGIN ENCRYPTED PRIVATE KEY-----
    MBQGCCqGSIb3DQMHBAgD1kGN4ZslJgSCBMi1xk9jhlPxPc
    9g73NQbtqZwI+9X5OhpSg/2ALxlCCjbqvzgSu8gfFZ4yo+
    A .... MANY LINES LIKE THAT .... 
    X0R+meOaudPTBxoSgCCM51poFgaqt4l6VlTN4FRpj+c/Wc 
    blK948UAda/bWVmZjXfY4Tztah0CuqlAldOQBzu8TwE7WD 
    H0ga/iLNvWYexG7FHLRiq5hTj0g9mUPEbeTXuPtOkTEb/0
    GEs=
    -----END ENCRYPTED PRIVATE KEY-----
    -----BEGIN CERTIFICATE-----
    MIIDXTCCAkWgAwIBAgIJAJC1HiIAZAiIMA0GCSqGSIb3Df
    BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVx 
    aWRnaXRzIFB0eSBMdGQwHhcNMTExMjMxMDg1OTQ0WhcNMT
    A .... MANY LINES LIKE THAT ....
    JjyzfN746vaInA1KxYEeI1Rx5KXY8zIdj6a7hhphpj2E04 
    C3Fayua4D
    RHyZOLmlvQ6tIChY0ClXXuefbmVSDeUHwc8Yu B7xxt8BVc69rLe
    HV15A0qyx77CLSj3tCx2IUXVqRs5mlSbvA==
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0
    BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA
    1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
    A .... MANY LINES LIKE THAT ....
    YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj
    CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
    -----END CERTIFICATE-----


    Additionally, for security reasons, the PEM-format certificate file and the directory where the file is located should not be readable by non-root users. For example:

    CODE
    drwxrw----. 2 root root 26 Apr 23 15:38 
    /etc/haproxy/ssl -r-------- 1 root root 7086 Mar 6 12:08 
    /etc/haproxy/ssl/certificatefile.pem
  3. censhare Server IP addresses or domain/hostnames and HTTPs ports: In the configuration example below, the servers are:

    CODE
    cust-prodns-css01 port 8082 
    cust-prodns-css02 port 8082
  4. censhare Server IP addresses or domain/hostnames and RMI ports: In the configuration example below, the servers are

    CODE
    cust-prodns-css01 port 30546 
    cust-prodns-css02 port 30546

Here is the complete /etc/haproxy/haproxy.cfg example which includes the items discussed above:

CODE
global
    log         127.0.0.1:514  local0  info
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon    tune.ssl.default-dh-param   2048
    ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
    ssl-default-bind-ciphers  ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
defaults
    log     global
    mode    http
    balance leastconn
    #option  tcplog
    log-format {"type":"haproxy","request_id":"%rt","timestamp":%Ts,"http_status":%ST,"http_request":"%r","remote_addr":"%ci/%cp","bytes_read":%B,"upstream_addr":"%si","bytes_uploaded":%U,"upstream_response_time":"%Tr","session_duration":"%Tt"}
    option  dontlognull
    option  redispatch
    option  log-health-checks
    retries 3
    maxconn 2000
    timeout connect  60000
    timeout client   60000
    timeout server   60000
    default-server inter 10s


###################### RMI Protocol Start ######################
frontend rmi30546-in
        mode tcp
        bind *:30546
        #option tcplog
        #option http-server-close
        default_backend rmi30546-out

backend rmi30546-out
        mode tcp
        stick-table type ip size 1m expire 30m
        stick on src
        balance leastconn
        default-server inter 1s downinter 3s rise 15 fall 15

        server cust-prodns-css01 cust-prodns-css01:30546 check
        server cust-prodns-css02 cust-prodns-css02:30546 check

###################### RMI Protocol Finish ######################

 
###################### HTTP/S Protocol Start ######################
frontend web80-in
        bind *:80
        http-request redirect code 301 location https://%[hdr(host)]/censhare5/client
        
frontend web443-in
    mode http
    bind *:443 ssl crt /etc/haproxy/ssl/cert_file.pem
    #option httplog  # not needed !!!
    # reqadd X-Forwarded-Proto:\ https
    default_backend cloud-gateway

    # Direct requests to REST interface directly to censhare-Server backend
    acl is_rest_interface path_beg /ws
    acl is_temp_download  path_beg /tempDownload
    use_backend web443-out  if  is_rest_interface
    use_backend web443-out  if  is_temp_download
    option forwardfor

    timeout client          300m
    timeout http-keep-alive 10s
    timeout http-request    5s
    timeout tarpit          60s  # KRED TODO Disable oder extend

    acl is_websocket path_beg /censhare5/client/
    acl is_websocket hdr(Upgrade) -i WebSocket
    acl is_websocket hdr_beg(Host) -i ws

    acl	path_auth           path    -m  beg /auth
    use_backend	keycloak    if  path_auth
    
    acl is_root path /

    capture request  header Host len 64

    http-request redirect scheme https code 301 if !{ ssl_fc }
    http-request redirect code 301 location https://%[hdr(host)]/censhare5/client if is_root
    

backend web443-out
    cookie SESSION prefix nocache
    option forwardfor
    balance leastconn

    option ssl-hello-chk

    option httpchk GET /monitoring/health
    http-check expect rstring ^{\"status\": \"UP\"}$
    default-server inter 1s downinter 3s rise 15 fall 15
    timeout check 1s

    timeout server          60s
    timeout tunnel        3600s
    timeout queue           30s
    timeout connect          5s
    #option http-server-close  # KRED es muss disabled

    http-request add-header X-Forwarded-Proto https if { ssl_fc }

    redirect scheme https if !{ ssl_fc }

    http-response add-header Strict-Transport-Security max-age=31536000;\ includeSubdomains
    http-response add-header X-Content-Type-Options nosniff
    http-response add-header X-XSS-Protection 1;\ mode=block
    http-response add-header Referrer-Policy no-referrer
    http-response set-header X-Frame-Options SAMEORIGIN
    http-response add-header Permissions-Policy accelerometer=(),\ ambient-light-sensor=(),\ autoplay=(),\ camera=(),\ display-capture=(),\ document-domain=(),\ fullscreen=(self),\ execution-while-not-rendered=(),\ execution-while-out-of-viewport=(),\ gyroscope=(),\ magnetometer=(),\ microphone=(),\ midi=(),\ payment=(),\ picture-in-picture=(),\ publickey-credentials=(),\ sync-xhr=(),\ usb=(),\ wake-lock=()

    server cust-prodns-css01 cust-prodns-css01:9443 weight 5 check ssl verify none cookie s1
    server cust-prodns-css02 cust-prodns-css02:9443 weight 5 check ssl verify none cookie s2

backend keycloak 
    cookie SESSION prefix nocache
    option forwardfor
    balance leastconn

    default-server inter 1s downinter 3s rise 15 fall 15
    timeout check 1s

    timeout server          60s
    timeout tunnel        3600s
    timeout queue           30s
    timeout connect          5s
    #option http-server-close  # KRED es muss disabled

    http-request add-header X-Forwarded-Proto https if { ssl_fc }
    redirect scheme https if !{ ssl_fc }
    server keycloak-server keycloak-server:9443 check cookie s1

backend cloud-gateway
    cookie SESSION prefix nocache
    option forwardfor
    balance leastconn

    option httpchk
    http-check expect status 302

    default-server inter 1s downinter 3s rise 15 fall 15
    timeout check 1s

    timeout server          60s
    timeout tunnel        3600s
    timeout queue           30s
    timeout connect          5s
    #option http-server-close  # KRED es muss disabled

    http-request add-header X-Forwarded-Proto https if { ssl_fc }
    redirect scheme https if !{ ssl_fc }


    http-response add-header Strict-Transport-Security max-age=31536000;\ includeSubdomains
    http-response add-header X-Content-Type-Options nosniff
    http-response add-header X-XSS-Protection 1;\ mode=block
    http-response add-header Referrer-Policy no-referrer
    http-response set-header X-Frame-Options SAMEORIGIN
    http-response add-header Permissions-Policy accelerometer=(),\ ambient-light-sensor=(),\ autoplay=(),\ camera=(),\ display-capture=(),\ document-domain=(),\ fullscreen=(self),\ execution-while-not-rendered=(),\ execution-while-out-of-viewport=(),\ gyroscope=(),\ magnetometer=(),\ microphone=(),\ midi=(),\ payment=(),\ picture-in-picture=(),\ publickey-credentials=(),\ sync-xhr=(),\ usb=(),\ wake-lock=()

    server cust-prodns-css01 cust-prodns-css01:8082 weight 5 check cookie s1
    server cust-prodns-css02 cust-prodns-css02:8082 weight 5 check cookie s1

###################### HTTP/S Protocol Finish ######################


###################### Statistics ######################
frontend statistics-8000
  bind *:8000
  mode http
  #option  httplog  # not needed !!!
  stats enable
  stats uri /haproxy
  stats auth admin:password
  stats admin if TRUE
###################### Statistics Finish ######################  

Validate the configuration file:

CODE
haproxy -f /etc/haproxy/haproxy.cfg -c

Fix any issues, then start HAProxy and make sure that it starts on server reboot:

CODE
systemctl enable haproxy && systemctl start haproxy

Redirects for censhare

If you use censhare with a load balancer, such as NGINX or HAProxy, set the following redirects:

  • Path "/auth/" to Keycloak ( http://authentication.your-company.com:8080 )

  • Path "/login/" to Cloud Gateway ( http://cloud-gateway.your-company.com:8082 )

  • Path "/oauth2/" to Cloud Gateway ( http://cloud-gateway.your-company.com:8082 )

  • Path "/censhare5/client/" to Cloud Gateway ( http://cloud-gateway.your-company.com:8082 )

  • Path "/ws/" to censhare-Server REST ( http://censhare.your-company.com:9000 )

  • Path "/tempDownload/" to censhare-Server REST ( http://censhare.your-company.com:9000 )

/tempDownload/ should be routed from the proxy directly to the censhare Server. As it does not have a separate mapping in the Cloud Gateway setup and does not use the usual login session.

Details and options

The following section contains details and explanations about the haproxy.cfg configuration file. Keep these configuration options, and customize them only if you are certain of the implications of the changes!

Load-balancing algorithms

HAProxy supports a number of load-balancing algorithms to determine how to distribute traffic to multiple backend servers.

The algorithm used above for HTTPs is leastconn:  The backend server with the least number of connections is used, and then for all servers with the same amount of connections, a round-robin is performed. The configuration entry:

CODE
balance leastconn


Currently, RMI cannot handle leastconn. Hence, sessions must be sent to the same backend server and be tracked by the client IP addresses. The configuration entry:

CODE
stick-table type ip size 1m expire 30m stick on src


Other algorithms are round-robin or static-rr. For more information on all supported load-balancing algorithms, see the   HAProxy Configuration Manual.

Sticky sessions

For the leastconn load-balancing algorithm, cookies are used to ensure that clients are always sent to the same backend server. The following lines in the backend section of the configuration file define this:

CODE
cookie SRVID insert indirect nocache maxidle 30m maxlife 1h 
... 
server cust-prodns-css01 cust-prodns-css01:8082 weight 5 check ssl verify none cookie s1 
server cust-prodns-css02 cust-prodns-css01:8082 weight 5 check ssl verify none cookie s2


Please also note the following parameters, which manage the timeout between the client (browser) and HAProxy, and HAProxy and the backend servers (censhare).

CODE
timeout client 60m 
... 
timeout server 60m

WebSocket

WebSocket support is required. The following configuration entries define this:

CODE
acl is_websocket path_beg /censhare5/client/ 
acl is_websocket hdr(Upgrade) -i WebSocket 
acl is_websocket hdr_beg(Host) -i ws

HAProxy statistics

The use of HAProxy statistics is optional but recommended. This is helpful for troubleshooting web traffic issues and for capacity planning.

To encrypt traffic for the statistics URL, use the following lines instead:

CODE
###################### Statistics ###################### 
fontend statistics-8443 
  bind *:8443 ssl crt /etc/haproxy/ssl/certificatefile.pem 
  mode http 
  #option httplog 
  stats enable 
  stats uri /haproxy 
  stats auth admin:password 
  stats admin if TRUE 
###################### Statistics Finish ######################

This uses the same PEM-encoded SSL certificate and the port 8443 that must be available.

CSP Headers

For security, you can also add Content-Security-Policy HTTP headers. For example:

CODE
http-response add-header Content-Security-Policy default-src\ 'none';\
http-response add-header Content-Security-Policy connect-src\ 'self'\ wss://%[capture.req.hdr(0)]\ 
https://nominatim.openstreetmap.org;\
http-response add-header Content-Security-Policy script-src\ 'self'\ 'unsafe-eval'\
https://connect.facebook.net\ 
https://platform.twitter.com\ 'sha256-mutaUHp7a6TAHBx7UkKbOet7lfkvyPk131k92oPYqEQ=';\
http-response add-header Content-Security-Policy img-src\ 'self'\ data:\
https://*.tile.openstreetmap.org;\
http-response add-header Content-Security-Policy worker-src\ 'self'\ blob:;\ 
     child-src\ 'self'\ blob:;\ style-src\ 'self'\ 'unsafe-inline';\ frame-src\ *;\ 
    media-src\ 'self';\ base-uri\ 'self';\ frame-ancestors\ 'self';\ form-action\ 
    'none';\ font-src\ 'self'\ data:;\ upgrade-insecure-requests


Restart HAProxy:

CODE
systemctl restart haproxy

SSL protocol versions

The HAProxy example configuration only allows HAProxy to accept TLSv1.2. The following entry in the configuration file removes the support for the SSL versions SSLv3, TLSv1.0 and TLSv1.1:

CODE
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets

Note on TLS 1.3

HAProxy 1.8 and newer introduce support for 0-RTT, also known as TLS 1.3. If a customer requires TLS 1.3 support, check if the current OS provides a compiled version of HAProxy 1.8. For example, you can check if the RPM repository contains this version. By default, RHEL/Alma Linux 9 7 do not include version 1.8 in their base repositories, but RHEL/Alma Linux 9 8 do.

If version 1.8 is not available in the base RPM repository, you must compile HAProxy from source.

Cipher suites

Supported cipher suites:

CODE
ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS

Further configuration

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.