HAProxy config tutorials

SSL / TLS

You can use Transport Layer Security (TLS) for encrypting traffic between the load balancer and clients. You can also encrypt traffic between the load balancer and backend servers. TLS is the successor to Secure Sockets Layer (SSL), which is now deprecated.

TLS between the load balancer and clients Jump to heading

For HTTPS, you will typically bind to port 443. In this setup, the load balancer handles encrypting and decrypting traffic, and sends traffic in the clear to backend servers. The backend servers can then listen on port 80 (HTTP port).

haproxy
frontend www
bind :443 ssl crt /certs/site.pem
default_backend webservers
haproxy
frontend www
bind :443 ssl crt /certs/site.pem
default_backend webservers

In this example:

  • The ssl argument enables TLS encryption.
  • The crt argument indicates the file path to a .pem file that contains both your server’s PEM-formatted TLS certificate and its private key. You will typically need to concatenate these two things manually into a single file. Simply copy and paste them into the file.
Setting crt to a directory

You can also set the crt argument to a directory. When set to a directory, the load balancer will use Server Name Indication (SNI) to search the directory for a certificate that has a Common Name (CN) or Subject Alternative Name (SAN) field that matches the requested domain, which the client sends during the TLS handshake.

This allows you to host multiple websites with different domain names at the same IP address and port. Each will use the certificate that matches the domain name being requested. In the example below, we set crt to a directory that contains TLS certificates:

haproxy
frontend www
mode http
bind :443 ssl crt /certs
default_backend webservers
haproxy
frontend www
mode http
bind :443 ssl crt /certs
default_backend webservers

Redirect HTTP to HTTPS Jump to heading

To enable an HTTP to HTTPS redirect, use the http-request redirect scheme directive:

haproxy
frontend www
mode http
bind :80
bind :443 ssl crt /certs/site.pem
http-request redirect scheme https unless { ssl_fc }
default_backend webservers
haproxy
frontend www
mode http
bind :80
bind :443 ssl crt /certs/site.pem
http-request redirect scheme https unless { ssl_fc }
default_backend webservers

In this example:

  • We set mode to http.
  • We enable TLS with the ssl and crt arguments on the second bind line. Notice that this frontend listens on both ports 80 for HTTP and 443 for HTTPS. Traffic that is received at HTTP port 80 is redirected to HTTPS port 443.
  • Use the http-request redirect scheme directive to redirect HTTP traffic to the HTTPS scheme, unless it is already HTTPS as indicated by the ssl_fc fetch method.

Info

Even with the redirect, there is still a chance that a man-in-the-middle attack can occur. To prevent this attack, consider using the http-response set-header Strict-Transport-Security directive. For details, see HTTP Strict Transport Security.

HTTP Strict Transport Security Jump to heading

Use HTTP Strict Transport Security (HSTS) to prevent a man-in-the-middle attack.

The HTTP Strict Transport Security (HSTS) policy directs clients to communicate over secure transport. This policy can prevent man-in-the-middle attacks, where the redirected traffic is intercepted by a malicious party.

HSTS works by sending the response header Strict-Transport-Security to clients. This header directs the client browser to use HTTPS instead of HTTP for this domain and, optionally, its subdomains.

Load balancer applications use the redirect scheme https directive to direct HTTP traffic to HTTPS, but that directive alone does not prevent a man-in-the-middle attack. Adding the HSTS header, however, prevents the man-in-the-middle attack by requiring the client to direct traffic to the secure site without relying on redirects. The client browser caches your domain’s HSTS policy so that for future HTTP requests, it automatically uses secure transport instead of HTTP.

The Strict-Transport-Security header fields are:

Field Description
max-age Required. Sets how long the browser should remember the rule, in seconds, after the user has visited the website at least once. The next time the user client accesses your domain, the HSTS policy will be cached again.
includeSubDomains Optional. Tells the browser that it should include all of your subdomains in the rule.
preload Optional. Submit your site to the HSTS preload service, which is a registry of websites that browsers will connect to using HTTPS automatically. The preload option requires includeSubDomains.

Enable HSTS Jump to heading

To enable HSTS:

  1. Configure the redirect to HTTPS in your frontend section.

  2. Insert the Strict-Transport-Security header into every response using the http-response set-header directive, as shown here:

    haproxy
    frontend www.mywebsite.com
    bind :80
    bind :443 ssl crt /etc/ssl/certs/mywebsite.com.pem
    http-request redirect scheme https code 301 unless { ssl_fc }
    # max-age is mandatory. 16000000 seconds is approximately 6 months. Use a low value during testing.
    http-response set-header Strict-Transport-Security "max-age=16000000; includeSubDomains; preload;"
    default_backend servers
    haproxy
    frontend www.mywebsite.com
    bind :80
    bind :443 ssl crt /etc/ssl/certs/mywebsite.com.pem
    http-request redirect scheme https code 301 unless { ssl_fc }
    # max-age is mandatory. 16000000 seconds is approximately 6 months. Use a low value during testing.
    http-response set-header Strict-Transport-Security "max-age=16000000; includeSubDomains; preload;"
    default_backend servers

With this configuration, HAProxy returns the Strict-Transport-Security header, which instructs the browser to route messages to this website using HTTPS from the start. This rule lasts for 16000000 seconds (approximately six months) after the user has visited your website at least once. From then on, attackers will no longer get a chance to intercept your user’s messages. As a side effect, it also avoids one round trip between the user and server, improving response times.

Info

During testing, use a low max-age value to minimize the impact on clients accessing any subdomains that do not yet support HTTPS. Once the HSTS policy is cached in the client’s browser, the browser will use only HTTPS to access your domain until the max-age expires. So until you’re sure all subdomains support HTTPS, use a low max-age value.

TLS between the load balancer and servers Jump to heading

To configure TLS between the load balancer and your backend servers, add the ssl and verify arguments to your server lines in a backend:

haproxy
backend webservers
mode http
balance roundrobin
server web1 10.0.0.5:443 ssl verify required ca-file /myca.pem
server web2 10.0.0.6:443 ssl verify required ca-file /myca.pem
haproxy
backend webservers
mode http
balance roundrobin
server web1 10.0.0.5:443 ssl verify required ca-file /myca.pem
server web2 10.0.0.6:443 ssl verify required ca-file /myca.pem

In this example:

  • The ssl argument enables TLS to the server.
  • The verify argument indicates whether to verify that the server’s TLS certificate was signed by a trusted Certificate Authority.
  • The ca-file argument sets the CA for validating the server’s certificate.

Typically, you will use port 443, which signifies the HTTPS protocol, when connecting to servers over TLS.

About the verify argument

Setting verify to required configures the load balancer to check the server’s certificate against a Certificate Authority (CA) certificate, which you specify with the ca-file argument. You can also set ca-file to @system-ca, in which case it will refer to the trusted CAs from your operating system.

You can also set verify to none, which means do not check that the server’s certificate is trusted. This is helpful when the server uses a self-signed certificate.

You can also include a crl-file parameter to indicate a certificate revocation list.

When mode is set to http, you can send an SNI value to your backend servers. Add the sni argument followed by a fetch method that returns the name you wish to use. Often, you will use the req.hdr fetch to get the Host header value, as shown below:

haproxy
backend webservers
server web1 10.0.0.5:443 ssl verify required ca-file /myca.pem sni req.hdr(Host)
server web2 10.0.0.6:443 ssl verify required ca-file /myca.pem sni req.hdr(Host)
haproxy
backend webservers
server web1 10.0.0.5:443 ssl verify required ca-file /myca.pem sni req.hdr(Host)
server web2 10.0.0.6:443 ssl verify required ca-file /myca.pem sni req.hdr(Host)

Global settings Jump to heading

Some TLS settings should apply to your entire load balancer, such as whether to allow older versions of TLS or whether to set a list of preferred ciphers. Although it’s possible to set these things at the bind or server level, you will often want to apply them across the board. In that case, you can add them to the global section of your configuration.

Set the minimum TLS version Jump to heading

The following example uses ssl-default-bind-options to allow only version TLS 1.2 or newer on all bind lines:

haproxy
global
ssl-default-bind-options ssl-min-ver TLSv1.2
haproxy
global
ssl-default-bind-options ssl-min-ver TLSv1.2

To set this on an individual bind line, use the ssl-min-ver argument.

Set the TLS ciphers Jump to heading

Use the ssl-default-bind-ciphers directive to set a list of TLS ciphers for bind lines, in order of preference:

haproxy
global
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
haproxy
global
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

To use the client’s preferred cipher instead, specify the prefer-client-ciphers parameter.

To set this on an individual bind line, use the ciphers argument.

For TLS versions 1.3 and later, set the preferred encryption ciphers in your global section using the ssl-default-bind-ciphersuites option. Note that you can override this value on each bind line (including bind lines in crt-list files).

haproxy
global
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
haproxy
global
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256

To set this on an individual bind line, use the ciphersuites argument.

Disable validation of certificates Jump to heading

When the load balancer connects to a backend server over HTTPS, the server presents its own certificate. To disable validation of server certificates, such as when using self-signed certificates, set the ssl-server-verify directive to none:

haproxy
global
ssl-server-verify none
haproxy
global
ssl-server-verify none

To set this on an individual server line, use the verify argument.

Performance considerations Jump to heading

Consider these factors when estimating TLS encryption performance:

  • Encryption with an ECC certificate uses about 1/8 of the CPU of an RSA certificate of an equivalent cryptographic strength.

    If you have both an ECC and RSA certificate, you can use both at the same time by using the file name extensions. Name the RSA certificate file with an .rsa extension, such as example.pem.rsa. Name the ECC certificate with an .ecdsa extension, such as example.pem.ecdsa. In your configuration, set the crt argument to load the file with only the .pem extension, omitting the .rsa or .ecdsa extension, such as crt example.pem.

  • How large are your RSA keys? 2048 is typical, 4096 will be substantially slower. The older 1024 is considered insecure and will no longer be signed by public CAs.

  • Are TLS session tickets enabled on the load balancer server? This can increase the speed of the TLS handshake.

The following guidelines can help you decide how many cores you need:

  • A 3.7GHz CPU core will take about 1ms to process a 2048 bit key exchange, meaning you can do 1000 key exchanges per second.
  • 1 GB of RAM can support 8000 open TLS connections.

If you decide that your use case will likely require more than one core, you can use the cpu-map options with nbthread to pin threads to specific cores.

For example:

haproxy
global
nbthread 4
cpu-map auto:1/1-4 0-3
haproxy
global
nbthread 4
cpu-map auto:1/1-4 0-3

OCSP Stapling Jump to heading

Available since

  • HAProxy 2.8
  • HAProxy Enterprise 2.8r1
  • Not available in HAProxy ALOHA

Note: As of version 2.8r1, when OCSP stapling is enabled, the load balancer will automatically update the OCSP response for its configured certificates. It will fetch the OCSP response from the URI contained within the certificate. For earlier versions, the OCSP response can be set manually using the set ssl ocsp-response command.

OCSP stapling is not available for HAProxy ALOHA.

The Online Certificate Status Protocol (OCSP) allows a client (browser) to see the revocation status of an SSL/TLS certificate in real time. A client contacts an OCSP Responder server to get the OCSP response, which contains the certificate’s revocation status. The Responder server is often managed by the certificate issuer.

Because the browser must make a separate call to the OCSP Responder server to fetch the certificate’s revocation status, OCSP adds a small delay to a user’s request. OCSP stapling is a mechanism that allows you to fetch the revocation status ahead of time and attach it to the certificate, saving the client from needing to make that request to the OCSP Responder server. The OCSP response contains a revocation status for the certificate of either good, revoked, or unknown.

Enable OCSP Stapling Jump to heading

When OCSP stapling is enabled, the load balancer will automatically retrieve and update the OCSP response for each of its configured certificates.

To enable OCSP stapling:

  1. Verify that the certificate contains an OCSP URI using the openssl x509 command. The output from this command shows the contents of the certificate. The output should contain a value named OCSP - URI under the section Authority Information Access.

    • To see the entire contents of the certificate:

      nix
      openssl x509 -in /etc/hapee-2.9/certs/newcert.pem -noout -text
      nix
      openssl x509 -in /etc/hapee-2.9/certs/newcert.pem -noout -text
      output
      text
      Certificate:
      Data:
      Version: 3 (0x2)
      Serial Number: 4104 (0x1008)
      Signature Algorithm: sha256WithRSAEncryption
      Issuer: C = AR, ST = AR, L = AR, O = AR, OU = AR, CN = AR, emailAddress = AR
      Validity
      Not Before: Aug 13 08:00:00 2015 GMT
      Not After : Aug 13 09:00:00 2025 GMT
      [...]
      X509v3 extensions:
      Authority Information Access:
      OCSP - URI:http://ocsp.issuer.com
      X509v3 Basic Constraints:
      CA:FALSE
      X509v3 Subject Key Identifier:
      88:40:3C:69:8F:93:0A:F6:62:CA:32:A8:D6:AA:0E:01:29:A3:6B:55
      X509v3 Authority Key Identifier:
      19:8C:C3:43:9A:02:8C:63:49:AA:AD:77:C9:68:06:B6:66:32:86:02
      [...]
      output
      text
      Certificate:
      Data:
      Version: 3 (0x2)
      Serial Number: 4104 (0x1008)
      Signature Algorithm: sha256WithRSAEncryption
      Issuer: C = AR, ST = AR, L = AR, O = AR, OU = AR, CN = AR, emailAddress = AR
      Validity
      Not Before: Aug 13 08:00:00 2015 GMT
      Not After : Aug 13 09:00:00 2025 GMT
      [...]
      X509v3 extensions:
      Authority Information Access:
      OCSP - URI:http://ocsp.issuer.com
      X509v3 Basic Constraints:
      CA:FALSE
      X509v3 Subject Key Identifier:
      88:40:3C:69:8F:93:0A:F6:62:CA:32:A8:D6:AA:0E:01:29:A3:6B:55
      X509v3 Authority Key Identifier:
      19:8C:C3:43:9A:02:8C:63:49:AA:AD:77:C9:68:06:B6:66:32:86:02
      [...]
    • To see only the value for OCSP - URI:

      nix
      openssl x509 -in /etc/hapee-2.9/certs/newcert.pem -text | grep "OCSP - URI"
      nix
      openssl x509 -in /etc/hapee-2.9/certs/newcert.pem -text | grep "OCSP - URI"
      output
      text
      OCSP - URI:http://ocsp.issuer.com
      output
      text
      OCSP - URI:http://ocsp.issuer.com
  2. OCSP settings must go into a crt-list file. A crt-list file enumerates the certificates bound to a listener and describes metadata about each certificate, such as ALPN, minimum TLS version, and OCSP. You can create a crt-list file, for example crt-list.txt, that has one line for each of the certificates you want to bind to. For example, if you host multiple websites at the same IP address, then you will add a line for each TLS certificate. Each line includes the path to the certificate. Your corresponding .ocsp file and issuer certificates should reside at this path as well.

    Note that the issuer certificate may be present in one of two ways:

    • It may have been issued with the certificate from your server chain, and so it will exist within your .pem file.
    • It may be its own file (sharing the same name as the server certificate and .ocsp files, but with the suffix .issuer).

    Your certificate (.pem) file should contain the following in this order:

    • public certificate
    • any intermediate certificates
    • private key
  3. Copy the certificate, corresponding issuer certificate (if it is a separate file), and corresponding .ocsp file to the directory you will specify in the crt-list (for example /etc/hapee-2.9/certs). You may need to create the directory if it does not already exist.

  4. Using the text editor of your choice, create the crt-list file. In this example, we will create a file named crt-list.txt in /etc/hapee-2.9/certs. For this example, we will specify one certificate.

    In the example crt-list file below, our PEM file is located at /etc/hapee-2.9/certs, as are our .ocsp and .issuer files. We are specifying our ALPN options here as well, alpn h2, and enabling OCSP with ocsp-update on. Note that the ocsp-update on parameter can be included only in a crt-list. It cannot be added to a bind line.

    crt-list.txt
    nix
    /etc/hapee-2.9/certs/newcert.pem [alpn h2 ocsp-update on]
    crt-list.txt
    nix
    /etc/hapee-2.9/certs/newcert.pem [alpn h2 ocsp-update on]
  5. Add a bind line to your frontend that specifies the path to the crt-list. The load balancer will load the certificates according to the options specified in the crt-list.

    haproxy
    frontend www
    bind :443 ssl crt-list /etc/hapee-2.9/certs/crt-list.txt
    default_backend webservers
    haproxy
    frontend www
    bind :443 ssl crt-list /etc/hapee-2.9/certs/crt-list.txt
    default_backend webservers
  6. Optional: set the global configuration parameters tune.ssl.ocsp-update.maxdelay and tune.ssl.ocsp-update.mindelay to specify the minimum and maximum intervals between automatic updates of the same OCSP response. Their defaults are 3600 seconds (1 hour) and 300 seconds (5 minutes), respectively. tune.ssl.ocsp-update.mindelay must be set to a value lower than that specified for tune.ssl.ocsp-update.maxdelay.

    haproxy
    global
    tune.ssl.ocsp-update.mindelay 300
    tune.ssl.ocsp-update.maxdelay 3600
    haproxy
    global
    tune.ssl.ocsp-update.mindelay 300
    tune.ssl.ocsp-update.maxdelay 3600
  7. Reload the load balancer configuration.

    nix
    sudo systemctl reload hapee-2.9-lb
    nix
    sudo systemctl reload hapee-2.9-lb

See also Jump to heading

Do you have any suggestions on how we can improve the content of this page?