Announcing HAProxy 3.3

HAProxy 3.3 is here, and this release brings downloadable packages compiled by HAProxy Technologies, numerous TLS enhancements including expanded ACME support, better observability with persistent stats over reloads, and many improvements to performance and flexibility such as support for QUIC on the backend. These powerful capabilities help HAProxy remain the G2 category leader in API Management, Container Networking, DDoS Protection, Web Application Firewall (WAF), and Load Balancing.

Our new downloadable HAProxy packages, compiled using the AWS-LC TLS library, provide the simplest way to get the latest and best-performing version of HAProxy for your flavor of Linux. HAProxy’s class-leading SSL/TLS processing is even better with support for ACME DNS-01 challenges, automatic SNI, Encrypted Client Hello, Linux Kernel TLS, and more. Persistent stats over reloads enabling continuous, uninterrupted metrics for dashboards and alerting systems. Improvements to default settings and CPU/memory management make HAProxy 3.3 the fastest and most efficient HAProxy yet. Experimental support for QUIC on the backend provides expanded interoperability and helps ensure future-proof compatibility with the QUIC protocol.

In this blog post, we’ll explore all the latest changes in detail. As always, enterprise customers can expect to find these features included in the next version of HAProxy Enterprise.

Register for our webinar HAProxy 3.3: Feature Roundup and listen to our experts as we examine new features and updates and participate in the live Q&A.

New to HAProxy?

HAProxy is the world’s fastest and most widely used software load balancer. It provides high availability, load balancing, and best-in-class SSL/TLS processing for TCP, QUIC, and HTTP-based applications.

HAProxy is the open source core that powers HAProxy One, the world’s fastest application delivery and security platform. The platform consists of a flexible data plane (HAProxy Enterprise) for TCP, UDP, QUIC and HTTP traffic; a scalable control plane (HAProxy Fusion); and a secure edge network (HAProxy Edge).

HAProxy is trusted by leading companies and cloud providers to simplify, scale, and secure modern applications, APIs, and AI services in any environment.

​How to get HAProxy 3.3

You can install HAProxy version 3.3 in any of the following ways:

Performance packages

We've added a new place where you can download packages for installing HAProxy. These packages are built with the AWS-LC TLS library, which performs best under heavy load. For that reason, we call these the performance packages. Currently, you can install packages for HAProxy 3.2 on Ubuntu 24.04, Debian 12, and Debian 13, with HAProxy 3.3 will be available here very soon. We'll keep them updated with the latest changes.

Get started with the performance packages here.

Security and TLS

HAProxy's robust security and SSL/TLS processing is improved in version 3.3 with a host of new features. This release adds expanded ACME support, automatic SNI, Encrypted Client Hello, and kTLS. It improves HAProxy’s ability to work with certificates protected by passphrases. We've also enhanced OAuth authentication.

ACME

HAProxy 3.3 extends the ACME implementation from version 3.2 by adding support for DNS-01 type validation challenges alongside the existing HTTP-01. A validation challenge is the method that ACME providers, such as Let's Encrypt, utilize to verify that you own the domain for which you're requesting a TLS certificate.

HAProxy supports this via the HAProxy Data Plane API version 3.3 (coming soon), which handles the communication between HAProxy and the DNS provider. During the DNS-01 challenge, the ACME provider sends a secret phrase that must be added as a DNS TXT record, establishing ownership of the domain. The HTTP-01 challenge accomplishes the same thing by adding the secret phrase to a file on the web server. In both scenarios, HAProxy and the HAProxy Data Plane API seamlessly automate the entire process.

Once the validation is complete, the ACME provider issues a TLS certificate. New in this version, the HAProxy Data Plane API will automatically store the certificate on the load balancer's filesystem, eliminating manual management. However, you should use this functionality only with single load balancer deployments. For multiple load balancer deployments or clusters, you'll need manual synchronization of the certificates, though HAProxy Fusion offers cluster-wide certificate management capabilities out of the box.

SNI

Configuring server-side TLS is now simpler as HAProxy can automatically set an SNI value from the host HTTP header and forward it to the backend server. Previously, this required manual configuration using sni req.hdr(host) on the server line. You can disable this automatic behavior by setting no-sni-auto on the server line, or explicitly re-enable it with sni-auto. Similarly, the check-sni-auto and no-check-sni-auto arguments allow explicit control of the automatic SNI value sent in health checks.

Also, you'll get a warning now if you try to use the strict-sni and default-crt arguments together on a bind directive in a frontend. This relates to setting default TLS certificates in your frontend: When you set a bind directive's crt argument to a directory instead of a single certificate file, HAProxy selects a certificate from that directory that has a CN or SAN field matching the SNI value the client sent. The default-sni argument lets you fall back to a default certificate if no other certificates match. Meanwhile, the strict-sni argument requires the SNI to match a certificate. The two don't make sense to use together and so are mutually exclusive.

Certificates with passphrases

A new global directive, ssl-passphrase-cmd, enables HAProxy to unlock TLS certificates that have a private key protected by a passphrase. The directive specifies a script that returns the passphrase when invoked with the key. HAProxy optimizes the process by trying all previously retrieved passphrases before re-invoking the script.

Encrypted Client Hello

A new, experimental bind argument, ech, enables HAProxy to use TLS ECH (Encrypted Client Hello). This new feature encrypts the ClientHello message sent to the load balancer, protecting sensitive fields including the SNI field, so they remain private and only decryptable by the target server. Using this argument requires the global directive expose-experimental-directives. Additionally, ECH requires clients to retrieve the public key from DNS, so first add your public key to your DNS configuration.

Kernel TLS

HAProxy 3.3 adds support for Kernel TLS, wherein the Linux kernel takes over handling the symmetric cryptography part of the TLS processing. It's beneficial because it allows HAProxy to offload cryptographic work to the kernel after it's performed the initial TLS handshake. The kernel handles further decryption and encryption without copying the data to HAProxy's userland process. Then data are encrypted/decrypted on the fly during the transfer from userland to the kernel. That in itself saves resources, particularly on high-speed links of 100 Gbps and above.

Even greater benefits come with end-to-end TLS, in which HAProxy manages TLS connections between itself and the client, and also between itself and the backend server. In that case, you can enable Kernel TLS on both ends. Then, optionally, enable kernel-based TCP splicing to transfer the data directly from the client socket to the server socket entirely at the kernel level without ever passing the data to the userland software, saving two memory copies!

You must compile HAProxy with flags for Kernel TLS and splicing, although both are enabled in the linux-glibc build target, which users commonly use. You'll need to run HAProxy with OpenSSL 3.x or the latest AWS-LC library. Set expose-experimental-directives in the global section. Add the ktls on argument to your bind directive and, if using end-to-end TLS, to your server directives. Then, to enable splicing, add option splice-auto to the frontend.

Preprocessor conditions

New preprocessor conditions help you to add sections to your configuration only when the statement is true.

Condition

Description

awslc_api_atleast(<ver>)

True if the current AWS-LC API number is at least as recent as "ver", otherwise false.

awslc_api_before(<ver>)

True if the current AWS-LC API number is strictly older than "ver", otherwise false.

ssllib_name_startswith(<name>)

True if the SSL library name HAProxy was linked with starts with "name".

OAuth authentication

HAProxy has supported validating JWTs (JSON Web Tokens) since version 2.5, which are necessary for OAuth 2.0 authentication. As part of the validation, HAProxy will, via the jwt_verify fetch method, check the signature embedded in the JWT against a public key that you got from the OAuth identity provider. However, providers often don't provide the keys directly, but embed them inside X.509 certificates. It had been a manual step to extract the key from the certificate. Now, with the new jwt_verify_cert fetch method, you can download the certificate and HAProxy will do the work of extracting the key from it, facilitating automation. 

To use a certificate with jwt_verify_cert, first declare it with a load directive in a crt-store section and set its jwt argument to on. The jwt argument is new in this version.

Other security changes

This version has a few other security-related changes:

  • You'll now get a warning at startup if you're running HAProxy as root and your configuration is missing the global directive user, which sets a Linux user account that HAProxy should run as. HAProxy runs with superuser privileges during initialization so that it can perform necessary tasks, such as binding to privileged ports, but afterwards, it's best if it can drop those privileges and become another user. The warning will nudge users towards adopting this security best practice. You could even set the user directive to root, but at least then it'd be explicit.

  • New bind and server arguments named tcp-md5sig adds support for Protection of BGP Sessions via the TCP MD5 Signature Option, which many routers require when placing a TCP proxy like HAProxy between them.

Observability

Better observability is a key focus of HAProxy 3.3. This version enables continuous, uninterrupted metrics for dashboards and alerting systems by introducing persistent stats over reloads. Tracing enhancements provide deeper insight into your load balancer's operations.

Persistent stats

You can now store frontend, backend, and server statistics in Linux's shared memory so that they can be preserved after reloading the configuration. These are the statistics you see on the Stats page and when calling the Runtime API command show stat. The feature is experimental, but the steps are:

  1. Add the expose-experimental-directives and shm-stats-file global directives.

  2. Add GUIDs to your frontends, backends, and servers. The GUIDs must be unique within your configuration.

  3. Reload HAProxy to see that the stats were preserved. Restarting it will lose the statistics.

Example configuration:

global
expose-experimental-directives
shm-stats-file /dev/shm/myshm
...
frontend example
guid a88e2a95-547e-47f1-b406-ea82ea47abcc
bind :80
use_backend webservers
backend webservers
guid 3db38dc1-4aa8-4172-b7de-affb7f1f51a8
server web1 172.16.0.12:80 check maxconn 30 guid 775e29c2-0b97-4f19-9976-dba604b833f4

Traces

The new acme and ssl trace sources let you monitor ACME and SSL events. In this example configuration, we start tracing ACME events, which will be sent to standard out:

traces
trace acme sink stdout level user event +any verbosity clean start now

Performance

Performance got a significant boost in this version, including changes to CPU policy, memory management, connection handling, and internal architecture for better efficiency.

  • The default load balancing algorithm is now random instead of roundrobin, when not otherwise set with the balance directive in a backend. This has demonstrated superior performance and improved fairness between uneven servers, but please read more about this change in this discussion. Note that the random algorithm works out of the box as a Power-of-Two algorithm, which allows it to randomly draw two servers from the list and then choose the least loaded one from those two.

  • HAProxy's cpu-policy now defaults to performance, meaning that on systems with a heterogenous mix of efficiency and performance core types, the load balancer will run on only the performance cores. For more information about cpu-policy, see tuning the load balancer’s automatic CPU binding. Also, HAProxy will automatically use all available cores and NUMA nodes on NUMA systems and the maximum number of threads is no longer limited to 64, which matters for machines that have more than 64 cores, particularly on non-NUMA systems. The increased processing capacity benefits CPU-intensive use cases such as TLS, Lua, and regex.

  • Frontend, backend, and server-related event counters are now stored per thread group, which reduces bottlenecks when accessing the counters.

  • Backends with mode http now set option abortonclose by default. This setting tries to stop processing a request before it's been sent to a server if the client aborted on their end, such as by closing the tab or refreshing. Also, you can now set option abortonclose in a frontend, which wasn't allowed before, and HAProxy will avoid computing the TLS handshake on connections that are already closed.

  • HAProxy saves resources by no longer allocating memory for a default-server directive unless you declare one in your configuration. Also, after parsing the directive, HAProxy releases the memory associated with it.

  • When using a use-server directive or track argument in a backend, startup will be faster now that HAProxy uses a more efficient algorithm for finding the server.

  • You can now choose a different TCP congestion algorithm by setting it with the new cc argument on a bind or server line.

  • This version relaxes the amount of locking between stick tables and peers by batching the updates and delaying work, leading to a smoother traffic flow and better overall performance.

  • Some multi-threaded tasks that caused a lot of contention on servers with many CPUs, such as stick table expirations and resolvers connections, were changed to be single threaded.

  • HAProxy's internal HTTP client, which it uses for tasks such as sending requests to ACME servers, had yielded control of the thread in between sending the HTTP headers and sending the HTTP body. That isn't necessary if HAProxy has the headers and body ready to send. In this release, HAProxy will send both, if possible.

  • In this version, the way that HAProxy connects to DNS nameservers was changed. Previously, if an outage caused by a main route to the nameservers being down might cause the packets to use an alternative route and interface, but then not revert to the main route once it became available again,  HAProxy will now correctly revert to using the main route. Instead of using the connect() and send() functions, HAProxy now performs a bind on the wildcard address for the datagram AF_INET* client socket, then uses sendto() instead of send().

  • Multithreaded applications may experience performance hits when multiple threads modify data, even if unrelated, in the same cache line, which may invalidate the cache line for other threads and cause a cache eviction. Updates to this version include some initial work towards optimizing HAProxy's memory allocation functions such that they align some objects and memory pools along cache line boundaries (64-byte chunks). Allocating memory aligned to the cache line boundaries helps keep data grouped by locality which prevents multiple threads thrashing the cache when the data is unaligned. This results in less contention, less locking, and fewer cache evictions.

  • In this version, the mechanisms reusing and purging server-side idle connections saw improvements. Connections created when http-reuse is set to never or when using Basic Authentication can now be purged, preventing resource leaks, and some related features, such as deleting a server via the HAProxy Runtime API, will work more reliably, as the servers' idle connections are now better managed.

Flexibility

HAProxy 3.3 brings many improvements to flexibility, such as experimental support for QUIC on the backend. Configuring the load balancer is now more flexible, with new fetch methods and converters, and enhancements to the HAProxy Runtime API.

HTTP/3

You can now connect to backend servers with HTTP/3 over QUIC. After ensuring that your backend web server supports HTTP/3 and has it enabled, configure HAProxy to use the protocol. Because it's an experimental feature, add the expose-experimental-directives global directive. Then, update your servers to use quic4@ before the address and set the TLS arguments.

backend webservers
server web1 quic4@172.16.0.11:443 check maxconn 30 ssl verify required ca-file /etc/haproxy/ssl/myca.pem

New QUIC-related global directives are available:

  • tune.quic.be.cc.cubic-min-losses

  • tune.quic.be.cc.hystart

  • tune.quic.be.cc.max-frame-loss

  • tune.quic.be.cc.max-win-size

  • tune.quic.be.cc.reorder-ratio

  • tune.quic.be.max-idle-timeout

  • tune.quic.be.sec.glitches-threshold

  • tune.quic.be.stream.data-ratio

  • tune.quic.be.stream.max-concurrent

  • tune.quic.be.stream.rxbuf

  • tune.quic.be.tx.pacing

  • tune.quic.be.tx.udp-gso

  • tune.quic.listen

  • tune.quic.mem.tx-max

The global directives that were prefixed with tune.quic.frontend still exist, but are deprecated in favor of the directives prefixed with tune.quic.fe. A few other QUIC directives were also deprecated, as the naming is consolidated.

Also in this version, the no-quic global directive has been renamed tune.quic.listen, which you can set to on or off to enable and disable the QUIC protocol.

Fetch methods

New fetch methods in this release are:

Fetch method

Description

req.bytes_in

An alias for bytes_in, this returns the number of bytes received from the client.

req.bytes_out

This returns the number of bytes sent to the server.

res.bytes_in

An alias for bytes_out, this returns the number of bytes received from the server.

res.bytes_out

This returns the number of bytes sent to the client.

Converters

New converters in this release are:

Converter

Description

base2

Converts a binary input sample to a binary string containing eight binary digits per input byte.

le2dec

Converts little-endian binary input sample to a string containing an unsigned integer number per a given chunk size of input bytes.

Also, the aes_gcm_dec and aes_gcm_enc converters now accept an optional AAD argument that's sometimes required for authentication.

Runtime API

The HAProxy Runtime API has these changes:

  • The add ssl crt-list command will no longer verify that the certificate's path matches its name in memory. That's because when using crt-store and crt-list together, you might assign aliases to your certificates, which wouldn't work with the previous path-based name validation. It's up to you to ensure that the certificate you're adding to the crt-list has the correct path, if not an alias.

  • The show dev command, which displays platform and environment information, now reports the thread-to-CPU bindings.

  • The show info command, which displays process information, now reports the number of added and removed lines in map and ACL files, to better detect scripts that continuously add entries, but don't remove entries as expected.

  • When calling the show stat command with the typed argument, it now shows next to each metric the letter V for volatile or P for persistent. These appear after the already existing origin, nature, and scope letters in the output. This is part of HAProxy's new support for persisting metrics across reloads.

Usability

HAProxy 3.3 makes life better with these usability improvements:

  • You can get the HAProxy version in different formats. Pass the command-line arguments -vq for version, -vqs for the short version, or -vqb for the branch.

  • If you've set the expose-experimental-directives global directive, but all of the experimental features you were using are no longer experimental, you'll get a reminder to remove the directive. That should help users in avoiding having experimental features enabled unintentionally.

  • The global directive dns-accept-family that was introduced in the last version now defaults to the value auto. This directive lets you disable IPv4 or IPv6 DNS resolution. A value of auto will enable IPv4 DNS resolution and check for IPv6 connectivity at startup, then again every 30 seconds to determine whether to enable IPv6 resolution.

  • Setting the global directive nbthreads to a total number of threads on which HAProxy should run while also declaring a thread-groups directive with a range of threads that exceeds that number will now emit a warning, and the missing threads will be removed. If a thread group is left with no threads at all, it causes a startup error.

  • For users who compile HAProxy statically, an error can arise if they then try to use the user and group global directives, due to a known limitation in  libc. HAProxy will now emit a warning at startup if it detects this. In this case, use the uid and gid directives instead.

  • Use the shell script haproxy-dump-certs to easily dump certificates from the HAProxy stats or master socket to the filesystem. Although, for those using the Data Plane API to enable ACME providers like Let's Encrypt, the API will save the certificates for you.

  • The directive tune.disable-fast-forward is no longer experimental, so you don't need to set expose-experimental-directives to use it. This directive was introduced in version 2.8 and disables data fast-forwarding.

  • For debugging, you may want to prevent all workers from being killed when a segfault occurs. You can use the global directive master-worker no-exit-on-failure.

  • The default number of reloads defined by mworker-max-reloads is now 50.

  • To build the halog utility, run make install-admin instead of make install. This change will help to ensure that users build halog with the correct options.

Modernization of subsystems

All applets, including the DNS, http-client, Lua, logs, peers, and Prometheus applets which were updated with this release, now maintain their own buffers rather than share buffers with the stream, which is used for socket reads and writes. Each applet having its own buffers requires less locking and improves synchronization, which reduces contention across the applets, improving the applets' scalability.

Deprecated features

These features are now deprecated, meaning they will be removed in a future version: 

  • The backend directives dispatch and option transparent are deprecated and will emit a warning to replace them if used.

  • Global directives prefixed with tune.quic.frontend are deprecated. Use the same directives prefixed with tune.quic.fe instead.

  • The master-worker global directive has been deprecated. Use the command-line arguments -W or -Ws instead.

Breaking changes

This version has the following breaking changes:

  • The minimum, default Linux kernel version, the one corresponding to the build target linux-glibc, has been updated to 4.17, which is a version older than all of the currently maintained LTS distros. This version was needed to support the new Kernel TLS feature.

  • The program section, which allows you to start and run an external program as a child process, was deprecated in version 3.1 and is now removed.

  • Using the same name for more than one frontend, backend, listen, defaults, or log-forward section is no longer allowed. Duplicated names, which have emitted a warning since version 3.1, will now emit an error at startup.

  • Using the same name for more than one server in a backend isn't allowed.

  • When configuring email alerts, you must enable the Lua implementation. If you add a mailers configuration section, but forget to load the Lua file, you'll get an warning.

  • The backend directive http-send-name-header, which lets you send the name of the server HAProxy is connecting to as an HTTP request header, had always let you decide which HTTP header to use for that purpose. But now, it won't allow you to choose the headers connection, content-length, host, or transfer-encoding. Overwriting those headers would only cause an invalid request.

  • When declaring an ACL, you can set the match type via the -m flag to explicitly compare the input value as a boolean, string, integer, etc. Specifying more than one match type after this flag is no longer allowed. Previously, HAProxy had silently used the last match type. Also, HAProxy will emit a warning when the match type is ambiguous, such as in path_beg -m reg. Is it matching the beginning of the path or using a regular expression?

  • This version renames the no-quic global directive to tune.quic.listen, which lets you enable or disable the QUIC transport protocol on all frontend listeners.

Conclusion

HAProxy 3.3 is a feature-rich release that continues to make application delivery simpler, more scalable, and more secure. This release improves SSL/TLS processing and automation, observability, performance, flexibility, and usability, benefiting organizations of all sizes with lower operational costs, increased operational efficiency, and more reliable services.

Did you know?

If you love HAProxy and want the ultimate HAProxy experience with next-gen security with multi-cloud management and observability, contact us for a demo of HAProxy One, the world’s fastest application delivery and security platform. 

As with every release, it wouldn’t have been possible without the HAProxy community. Your feedback, contributions, and passion continue to shape the future of HAProxy. So, thank you!

Ready to upgrade or make the move to HAProxy? Now’s the best time to get started.

Additional contributors: Nick Ramirez, Iwan Price-Evans

Subscribe to our blog. Get the latest release updates, tutorials, and deep-dives from HAProxy experts.