Skip to content

Last updated: 2026-02-11

HAProxy TLS/SSL Configuration Guide

This guide provides recommended TLS/SSL settings for HAProxy, a widely used high-performance load balancer and reverse proxy. HAProxy handles TLS termination at the frontend, offloading encryption from backend servers.

Prerequisites

HAProxy expects the certificate and private key in a single PEM file by default:

cat fullchain.pem privkey.pem > /etc/haproxy/certs/example.com.pem
chmod 600 /etc/haproxy/certs/example.com.pem

Global TLS Defaults

Set secure TLS defaults in the global section of your HAProxy configuration (/etc/haproxy/haproxy.cfg). These apply to all frontends unless overridden.

Protocol Versions

Set the minimum TLS version to 1.2 and disable session tickets:

global
    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
    ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets

Cipher Suites

Configure strong cipher suites for TLS 1.2 and TLS 1.3:

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
    ssl-default-bind-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
    ssl-default-server-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
    ssl-default-server-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256

Note: On HAProxy 1.8 (e.g. RHEL 8), ssl-min-ver, ssl-default-bind-ciphersuites, and ssl-default-server-ciphersuites are not available. Use the following instead to enforce TLS 1.2+ with ticket disabling: ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets and ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets. Omit the ciphersuites lines entirely — TLS 1.3 cipher selection will use OpenSSL defaults.

Frontend Configuration

Configure your HTTPS frontend with the certificate and ALPN protocol negotiation:

frontend https
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem alpn h2,http/1.1
    mode http

    # HSTS header
    http-response set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

    default_backend servers

The alpn h2,http/1.1 parameter enables HTTP/2 and HTTP/1.1 negotiation via ALPN.

Using a Certificate Directory

If you serve multiple domains, point to a directory containing all certificate PEM files:

frontend https
    bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1

HAProxy will automatically match certificates to hostnames via SNI.

HTTPS Redirect

Redirect all HTTP traffic to HTTPS:

frontend http
    bind *:80
    mode http
    http-request redirect scheme https code 301

Backend TLS (Re-encryption)

If your backends also require TLS (end-to-end encryption), configure the backend with TLS verification:

backend servers
    mode http
    server web1 10.0.0.1:443 ssl verify required ca-file /etc/haproxy/ca.pem check
    server web2 10.0.0.2:443 ssl verify required ca-file /etc/haproxy/ca.pem check

Use verify required with a ca-file to validate backend server certificates. Use verify none only if backends are on a fully trusted network.

OCSP Stapling

HAProxy supports OCSP stapling. Generate an OCSP response and reference it on the bind line:

frontend https
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem crt-list /etc/haproxy/crt-list.cfg alpn h2,http/1.1

In the certificate list file (crt-list.cfg):

/etc/haproxy/certs/example.com.pem [ocsp-update on] example.com

Note: ocsp-update on requires HAProxy 2.8+. On older versions, use openssl ocsp to fetch responses manually and load them via the HAProxy runtime API.

Complete Configuration Example

global
    # HAProxy 1.8 (RHEL 8): replace ssl-min-ver lines with no-sslv3 no-tlsv10 no-tlsv11
    # and remove the ciphersuites lines (see note above)
    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
    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
    ssl-default-bind-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
    ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets
    ssl-default-server-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
    ssl-default-server-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256

defaults
    mode http
    timeout connect 5s
    timeout client 30s
    timeout server 30s

frontend http
    bind *:80
    http-request redirect scheme https code 301

frontend https
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem alpn h2,http/1.1
    http-response set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    default_backend servers

backend servers
    server web1 10.0.0.1:8080 check
    server web2 10.0.0.2:8080 check

Verification

Test your configuration before reloading:

haproxy -c -f /etc/haproxy/haproxy.cfg
systemctl reload haproxy

Check the active TLS settings:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject

Test your configuration externally using Qualys SSL Labs at https://www.ssllabs.com/ssltest/.