SSL/TLS

Basics of enabling TLS

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

Client-side TLS Jump to heading

The load balancer offers you flexibility in regards to enabling TLS for your frontends. The needs of your application, configuration, and certificate storage (where you store your certificates, keys, and other related files on your filesystem) may determine which configuration concept you should use. There are three configuration options to consider.

Option Availability Description
crt
  • All versions

Setting the crt argument on a bind line in a frontend section offers the simplest way to enable TLS. In its most basic form, you’ll set this argument to the path to a PEM file that contains your certificate and key. Optionally, you can also set it to a directory path, and HAProxy will search the directory for the PEM file to use based on the SNI received during the TLS handshake with the client. When configuring additional options, such as OCSP stapling, you’ll need to use a crt-store or crt-list instead.

See Use crt to enable TLS.

crt-store
  • HAProxy 3.0 and newer
  • HAProxy Enterprise 3.0r1 and newer
  • HAProxy ALOHA 16.5 and newer

The crt-store configuration section separates the declarations of where certificates are stored from their use in a frontend. Its purpose is to provide additional flexibility regarding the location of related certificate files, key files, and so on. You can use a crt-store to specify different filesystem locations for certificate and key files and assign aliases to certificates for easier readability when referenced in the frontend or in crt-list files.

See Use crt-store to enable TLS.

crt-list
  • All versions

You can specify a separate crt-list file in place of multiple crt declarations if you need to apply different SSL configuration options per certificate. This file contains a list of certificates and their associated settings, each on its own line in the file. Then, you’ll reference the whole file on your bind line. All of the certificate files, key files, and OCSP files must be co-located, as is the case with crt. For newer implementations, prefer crt-store, which lets you configure settings within the configuration file and doesn’t depend on external crt-list files.

See crt-list in the configuration manual.

See Configuration considerations to help you decide which configuration concept is best suited for your application.

Use crt to enable TLS Jump to heading

For HTTPS, you will typically bind to port 443. In the following setups, 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).

You can configure the crt setting either using a single PEM file or a directory with multiple files.

Set crt to a single PEM file Jump to heading

haproxy
frontend example
bind :443 ssl crt /certs/site.pem
default_backend webservers
haproxy
frontend example
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.

Set crt to a directory Jump to heading

You can also set the crt argument to a directory to use separate certificate and key files, instead of a single PEM file. 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 example
mode http
bind :443 ssl crt /certs
default_backend webservers
haproxy
frontend example
mode http
bind :443 ssl crt /certs
default_backend webservers

Use crt-store to enable TLS Jump to heading

This section applies to:

  • HAProxy 3.0 and newer
  • HAProxy Enterprise 3.0r1 and newer
  • HAProxy ALOHA 16.5 and newer

You can configure the load balancer’s internal certificate storage mechanism using a crt-store. The crt-store separates certificate storage from their use in a frontend and provides better visibility for certificate information by moving it from external files, such as within a crt-list, and placing it into the main HAProxy configuration. The crt-store section allows you to individually specify the locations of each certificate component, such as certificate, key, and OCSP response files.

To use a crt-store:

  1. Define a crt-store section in your load balancer configuration. Consider the following example.

    haproxy
    crt-store mycertificates
    crt-base /etc/haproxy/ssl/certs/
    key-base /etc/haproxy/ssl/private/
    load crt "site1.crt"
    load crt "site2.crt" key "site2.key"
    haproxy
    crt-store mycertificates
    crt-base /etc/haproxy/ssl/certs/
    key-base /etc/haproxy/ssl/private/
    load crt "site1.crt"
    load crt "site2.crt" key "site2.key"

    In this example:

    • The crt-store section named mycertificates loads the TLS certificates that the load balancer will use.
    • The crt-base directive specifies the directory to search for TLS certificate files. In this example, files are located at /etc/haproxy/ssl/certs.
    • The key-base directive specifies the directory to search for key files. In this example, files are located at /etc/haproxy/ssl/private.
    • Each load directive refers to a certificate file and options that pertain to it.
  2. Use certificates from a crt-store in a frontend by referencing them by name via a bind directive’s crt argument. The format for the name is @<crt-store name>/<certificate name or alias>, or in this case, @mycertificates/site1.crt and @mycertificates/site2.crt. When you specify more than one certificate, the load balancer chooses one for the current request based on SNI.

    haproxy
    frontend example
    bind :443 ssl crt "@mycertificates/site1.crt" crt "@mycertificates/site2.crt"
    haproxy
    frontend example
    bind :443 ssl crt "@mycertificates/site1.crt" crt "@mycertificates/site2.crt"

You can also specify the crt-base and key-base in your global settings. Note that including crt-base or key-base in a crt-store take precedence over the global settings. The same is true for using absolute paths when specifying your certificates and keys.

See the load reference for options available for the load directive.

Info

If you don’t give your crt-store a name, you can reference its certificates using @/<certificate name or alias>, leaving out of the name of the crt-store. For example, @/site1.crt for a certificate named site1.crt defined in an unnamed crt-store.

Update certificate files dynamically

You can update certificate files dynamically using Runtime API commands including set ssl cert. See Update an ssl certificate using the runtime API for more information.

Use aliases Jump to heading

Aliases provide support for human-friendly names for referencing the certificates more easily on bind lines. To use aliases:

  1. Define a crt-store section in your configuration. In the example below, we name our crt-store mycertificates.

    haproxy
    crt-store mycertificates
    crt-base /etc/haproxy/ssl/certs
    load crt "site1.pem" ocsp "site1.ocsp" alias "site1" ocsp-update on
    haproxy
    crt-store mycertificates
    crt-base /etc/haproxy/ssl/certs
    load crt "site1.pem" ocsp "site1.ocsp" alias "site1" ocsp-update on
  2. In the load directive of your crt-store, give your crt an alias using the alias option. In this example, we give the certificate named site1.pem an alias of site1.

    haproxy
    crt-store mycertificates
    crt-base /etc/haproxy/ssl/certs
    load crt "site1.pem" ocsp "site1.ocsp" alias "site1" ocsp-update on
    haproxy
    crt-store mycertificates
    crt-base /etc/haproxy/ssl/certs
    load crt "site1.pem" ocsp "site1.ocsp" alias "site1" ocsp-update on

    Note that in this example we also specify that the certificate’s corresponding OCSP response file is named site1.ocsp. We enable OCSP stapling for this certificate by including the option ocsp-update and setting it to on.

  3. Reference the certificate components defined in the crt-store by the alias site1 in a frontend:

    haproxy
    frontend example
    bind :443 ssl crt "@mycertificates/site1"
    default_backend webservers
    haproxy
    frontend example
    bind :443 ssl crt "@mycertificates/site1"
    default_backend webservers

    In this frontend, we set the crt as @mycertificates/site1. This means that:

    • We are using the crt-store named mycertificates.
    • From the crt-store named mycertificates, we want the certificate components having the alias site1. In this case, as we defined in the crt-store, that is the certificate site1.pem and OCSP response file site1.ocsp.

Use ssl-f-use Jump to heading

This section applies to:

  • HAProxy 3.2 and newer
  • HAProxy Enterprise 3.2r1 and newer
  • HAProxy ALOHA 17.5 and newer

The ssl-f-use directive uses a certificate from a crt-store section in a frontend. With it, you can associate the certificate with properties like minimum TLS version to allow, ALPN fields, ciphers, signature algorithms, the CA file to use for client certificate verification, and others. In previous versions, if you wanted to define properties for multiple certificates in a frontend, you’d have to use an external crt-list file. It wasn’t possible to set different properties for multiple certificates on a bind line. Now, you can configure one or more ssl-f-use directives to set properties unique to each of the certificates you want to use, without needing an external crt-list file.

  1. Define a crt-store section in your load balancer configuration. For example:

    haproxy
    crt-store mycertificates
    crt-base /etc/haproxy/ssl/certs/
    key-base /etc/haproxy/ssl/private/
    load crt "site1.pem" alias "site1"
    load crt "site2.crt" key "site2.key" alias "site2"
    haproxy
    crt-store mycertificates
    crt-base /etc/haproxy/ssl/certs/
    key-base /etc/haproxy/ssl/private/
    load crt "site1.pem" alias "site1"
    load crt "site2.crt" key "site2.key" alias "site2"
  2. In your frontend section, add ssl-f-use directives that refer to the PEM files loaded in the crt-store section. Note that the bind line no longer needs to set a crt argument. When you specify more than one ssl-f-use directive, the load balancer chooses the appropriate certificate for the current request based on SNI.

    haproxy
    frontend example
    bind :443 ssl
    ssl-f-use crt "@mycertificates/site1" ssl-min-ver TLSv1.2
    ssl-f-use crt "@mycertificates/site2" ssl-min-ver TLSv1.3
    default_backend webservers
    haproxy
    frontend example
    bind :443 ssl
    ssl-f-use crt "@mycertificates/site1" ssl-min-ver TLSv1.2
    ssl-f-use crt "@mycertificates/site2" ssl-min-ver TLSv1.3
    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 example
mode http
bind :80
bind :443 ssl crt /certs/site.pem
http-request redirect scheme https unless { ssl_fc }
default_backend webservers
haproxy
frontend example
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.

Set default certificates Jump to heading

This section applies to:

  • HAProxy 3.0 and newer
  • HAProxy Enterprise 3.0r1 and newer
  • HAProxy ALOHA 16.5 and newer

If you specify the crt as 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. If the client doesn’t provide an SNI or if the SNI hostname doesn’t match any certificate, the load balancer will present a default certificate. You can specify default certificates on your bind line using the default-crt option.

To set a default certificate:

  • Add the default-crt option to the bind line in your frontend, specifying the names of your default certificates. Note that you can specify multiple default certificates, for example, an ECDSA certificate and an RSA certificate. Specifying multiple certificates in this way will allows you to give precedence to the ECDSA certificate, presenting the RSA certificate otherwise.

    haproxy
    frontend example
    bind :80
    bind :443 ssl default-crt /certs/default.pem.ecdsa /certs/default.pem.rsa crt /certs/
    # Redirects to HTTPS
    http-request redirect scheme https unless { ssl_fc }
    haproxy
    frontend example
    bind :80
    bind :443 ssl default-crt /certs/default.pem.ecdsa /certs/default.pem.rsa crt /certs/
    # Redirects to HTTPS
    http-request redirect scheme https unless { ssl_fc }

    In this example:

    • We specify the default certificates as /certs/default.pem.ecdsa and /certs/default.pem.rsa. The load balancer will try to use the ECDSA certificate first, and if unsupported by the client, use the RSA certificate.
    • We set the directory for our certificates as /certs/. The load balancer will select the appropriate certificate from this directory based on the SNI. If it cannot find a matching certificate, it will use the default certificates.

Note that the load balancer will use default certificates only when you aren’t also using the strict-sni option.

Other ways to set default certificates

If you don’t explicitly define your default certificates using the default-crt directive, the load balancer will try to select and load a default certificate in one of the following ways:

  • The load balancer will use the first certificate in the directory. If you intend to load default certificates in this way, ensure that this first certificate file is a multi-cert bundle (PEM format).

  • If you are using a crt-list, mark your certificate with an asterisk to indicate that the load balancer should consider it to be the default. For example:

    crt-list.txt
    nix
    default.pem.rsa *
    default.pem.ecdsa *
    crt-list.txt
    nix
    default.pem.rsa *
    default.pem.ecdsa *

HTTP Strict Transport Security Jump to heading

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

The 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 doesn’t 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.

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 example
    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 webservers
    haproxy
    frontend example
    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 webservers

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 16,000,000 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 don’t 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.

Server-side TLS Jump to heading

You can encrypt traffic between the load balancer and backend servers. TLS is the successor to the deprecated Secure Sockets Layer (SSL).

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 (CA).
  • 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 don’t 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)

HAProxy 3.3 sets the SNI

With HAProxy 3.3 / HAProxy Enterprise 3.3r1 / HAProxy ALOHA 18.0 and newer, the SNI value is set automatically to the Host request header, so you don’t need to set the sni argument. To disable this behavior, add no-sni-auto to the server line. The SNI is also set automatically for HTTP health checks, but you can disable that with the no-check-sni-auto 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.

Depending on your specific hardware and the characteristics of your traffic, there may be additional tuning you can do to optimize performance. See the performance optimization for large systems configuration guide.

Configuration considerations Jump to heading

In some cases, you can use either a crt-list or a crt-store depending on your configuration needs. You can also provide some of the same options those settings provide when defining a crt on the bind line. With multiple options for configuration, which one should you choose? The answer depends on the needs of your application, configuration, and certificate storage.

Here are some common use cases with which setting you should consider using:

  • You want to specify different filesystem locations for certificates and keys.

    • Consider using a crt-store, as it allows you to specify independent locations for related certificate files, key files, OCSP response files, and so on. If you use only crt without crt-store or use crt-list, the load balancer assumes all of the files are co-located with the certificate.
  • You want to set specific SSL options per certificate.

    • Consider using a crt-list, as it allows you to specify different options per certificate. The crt-list also supports several parameters from the crt-store load directive.
  • You want to use aliases but also want to be able to set specific SSL options per certificate.

    • Consider using crt-store in combination with a crt-list. In this way, you can specify the storage locations for your certificate components and give the certificates aliases. Using the aliases you defined in the crt-store, you can then add additional SSL options to each certificate entry in the crt-list, referenced by aliases. For example:

      haproxy
      frontend example
      bind :443 ssl crt-list /etc/haproxy/certs/crt-list.txt
      default_backend webservers
      crt-store
      crt-base /etc/haproxy/ssl/certs/
      key-base /etc/haproxy/ssl/private/
      load crt "site1.crt" key "site1.key" ocsp "site1.ocsp" alias "site1"
      load crt "site2.crt" key "site2.key" alias "site2"
      load crt "site3.crt" key "site3.key" alias "site3"
      haproxy
      frontend example
      bind :443 ssl crt-list /etc/haproxy/certs/crt-list.txt
      default_backend webservers
      crt-store
      crt-base /etc/haproxy/ssl/certs/
      key-base /etc/haproxy/ssl/private/
      load crt "site1.crt" key "site1.key" ocsp "site1.ocsp" alias "site1"
      load crt "site2.crt" key "site2.key" alias "site2"
      load crt "site3.crt" key "site3.key" alias "site3"
      crt-list.txt
      haproxy
      @/site1 [ciphers ECDHE-ECDSA-AES256-GCM-SHA384 ssl-min-ver TLSv1.2]
      @/site2 [ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256 ssl-min-ver TLSv1.3]
      @/site3 [ciphers ECDHE-RSA-AES128-GCM-SHA256]
      crt-list.txt
      haproxy
      @/site1 [ciphers ECDHE-ECDSA-AES256-GCM-SHA384 ssl-min-ver TLSv1.2]
      @/site2 [ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256 ssl-min-ver TLSv1.3]
      @/site3 [ciphers ECDHE-RSA-AES128-GCM-SHA256]

      Each certificate is referenced by alias in the crt-list. The frontend configuration references the crt-list rather than each certificate individually.

  • You have multiple certificates but don’t want to define your certificates in an external file, as would be the case with a crt-list, and you don’t need to use the SSL options supported by crt-list.

    • Consider using a crt-store. It enables you to put all of your certificate definitions into your main load balancer configuration file rather than list them in an external crt-list file.
  • You have a single certificate per frontend, don’t require OCSP stapling, and your related certificate and key files are co-located and share a name, such as site1.crt and site1.key.

    • Consider using crt on your bind line. It may be unnecessary for you to use a crt-store or crt-list if you don’t require additional options regarding storage or SSL configuration options.

See also Jump to heading

  • To enable SSL deciphering, see ssl.
  • To specify a PEM file for a bind, or the directory containing the certificate and associated private keys, see crt.
  • To specify a file containing a list of certs, see crt-list.
  • For enhanced flexibility in managing certificates, see crt-store.
  • To perform redirects such as redirecting HTTP requests to HTTPS, see http-request redirect.
  • To set the default behavior for SSL verification on the server side, see ssl-server-verify.
  • To specify a PEM file containing a CA certificate, see ca-file reference.
  • To specify whether the server certificate should be verified, see verify reference.
  • To bind a thread or thread group to a CPU, see cpu-map.

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