Example HAProxy Load-Balancer Configuration

You can use a HAProxy as a load balancer in PrivX-HA deployments. This article provides an example configuration for an HAProxy load balancer running on Rocky Linux.

In the following examples the IP addresses 192.0.2.100 and 192.0.2.101 need to be substituted with your PrivX-server addresses.

The sample configuration requires that the SELinux policy allows HAProxy process to listen at ports 1080, 2222 and 3389. Run the following commands to add these ports to the list of allowed listen ports for HAProxy:

semanage port -a -t http_port_t -p tcp 1080
semanage port -a -t http_port_t -p tcp 2222
semanage port -a -t http_port_t -p tcp 3389

HTTP, HTTPS ports, and port 8443 for client-certificate authentication should already be allowed by default.

You will also need to open firewall ports for incoming connections, for example:

firewall-cmd --zone=public --permanent --add-service=http
firewall-cmd --zone=public --permanent --add-service=https
firewall-cmd --zone=public --permanent --add-port=1080/tcp
firewall-cmd --zone=public --permanent --add-port=2222/tcp
firewall-cmd --zone=public --permanent --add-port=3389/tcp
firewall-cmd --zone=public --permanent --add-port=8443/tcp
firewall-cmd --reload

Additionally, the sample configuration requires you to install a TLS key and certificate to the following paths respectively:

/etc/ssl/certs/privx-lb.crt.key
/etc/ssl/certs/privx-lb.crt

After installing, you can set the following HAProxy configuration to /etc/haproxy/haproxy.cfg to satisfy all the load-balancer requirements described in PrivX high availability deployment:

# HAProxy load-balancer example configuration.
# Requests are distributed between servers using sticky sessions.
# In this example two instances of PrivX are running
# with private IP addresses 192.0.2.100 and 192.0.2.101
# HTTP requests except for CRLs are redirected to HTTPS.
#
# See the full configuration options online.
#
#   https://www.haproxy.org/download/1.8/doc/configuration.txt
#
#---------------------------------------------------------------------

#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    # to have these messages end up in /var/log/haproxy.log you will
    # need to add the following to /etc/rsyslog.d/99-haproxy.conf:
    # $AddUnixListenSocket /var/lib/haproxy/dev/log
    # # Send HAProxy messages to a dedicated logfile
    # :programname, startswith, "haproxy" {
    # /var/log/haproxy.log
    # stop
    # }

    log         /dev/log/ local0

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

    # utilize system-wide crypto-policies
    ssl-default-bind-ciphers PROFILE=SYSTEM
    ssl-default-server-ciphers PROFILE=SYSTEM

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    log                     global
    option                  dontlognull
    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

# Windows smartcard CRL and web traffic redirect port
frontend privx_lb_http
    bind *:80
    mode http
    option httpchk GET /authorizer/api/v1/cas

    option httplog    
    option http-server-close
    option forwardfor       except 127.0.0.0/8

    default_backend       privx_http

# PrivX https port
# Needs to be 'mode http' for PrivX components
frontend privx_lb_https
    bind *:443 ssl crt /etc/ssl/certs/privx-lb.crt ssl-min-ver TLSv1.3
    mode http
    
    option httpchk GET /monitor-service/api/v1/instance/status

    option httplog
    option http-server-close
    option forwardfor       except 127.0.0.0/8

    default_backend        privx_https

# Native clients and certificate authentication
# 'mode tcp' required for native protocol traffic
frontend privx_lb_native_ssh
    bind *:2222
    mode tcp

    option  tcplog

    default_backend       privx_native_ssh

frontend privx_lb_native_rdp
    bind *:3389
    mode tcp

    option tcplog  

    default_backend       privx_native_rdp

frontend privx_lb_client_certificate_auth
    bind *:8443
    mode tcp

    option tcplog

    default_backend       privx_client_certificate_auth

frontend privx_lb_native_ssh_proxy
    bind *:1080
    mode tcp

    option tcplog
 
    default_backend       privx_native_ssh_proxy

#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------

# Windows smartcard CRL endpoint and url redirection http -> https
backend privx_http
    mode http
    balance     roundrobin
    server node1 192.0.2.100:80 
    server node2 192.0.2.101:80

backend privx_https
    mode http

    # Health check PrivX instance endpoint.
    option httpchk GET /monitor-service/api/v1/instance/status

    # 'balance roundrobin' is required by PrivX components
    balance roundrobin

    # Sticky sessions are required by PrivX components. 
    # Setting the affinity cookie name to 'route', so no additional cookie configuration needed for PrivX components config files.
    cookie route insert indirect nocache  

    # Backend SSL cert not verified, you should consider using 'verify required' in production environments.
    server node1 192.0.2.100:443 check inter 30s ssl verify none cookie node1
    server node2 192.0.2.101:443 check inter 30s ssl verify none cookie node2

# Native client traffic can use whatever load balancing, using roundrobin in this example.
backend privx_native_ssh
    mode tcp

    stick-table type ip size 1m expire 8h
    stick on src
    balance roundrobin

    server node1 192.0.2.100:2222 check inter 30s
    server node2 192.0.2.101:2222 check inter 30s
   
backend privx_native_rdp
    mode tcp

    stick-table type ip size 1m expire 8h
    stick on src
    balance roundrobin

    server node1 192.0.2.100:3389 check inter 30s
    server node2 192.0.2.101:3389 check inter 30s
  
backend privx_client_certificate_auth
    mode tcp
    
    stick-table type ip size 1m expire 8h
    stick on src
    balance roundrobin

    server node1 192.0.2.100:8443 check inter 30s
    server node2 192.0.2.101:8443 check inter 30s

backend privx_native_ssh_proxy
    mode tcp
    
    stick-table type ip size 1m expire 8h
    stick on src
    balance roundrobin

    server node1 192.0.2.100:1080 check inter 30s
    server node2 192.0.2.101:1080 check inter 30s

Then reload the HAProxy configuration with:

# systemctl reload haproxy

Known issues

When connecting to a host using a native SSH or RDP client rather than the PrivX web UI, the load balancer's IP address is stored into audit logs instead of the client's IP address. There is currently no workaround for this.

Was this page helpful?

On this page