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:
Install the new HAProxy packages for Ubuntu / Debian (version 3.3 available here soon).
Run it as a Docker container. View the Docker installation instructions.
(Note that Docker containers built with the HAProxy performance packages with AWS-LC will be available later.)
Compile it from source. View the compilation instructions.
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 |
| True if the current AWS-LC API number is at least as recent as "ver", otherwise false. |
| True if the current AWS-LC API number is strictly older than "ver", otherwise false. |
| 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 theuserdirective to root, but at least then it'd be explicit.New
bindandserverarguments namedtcp-md5sigadds 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:
Add the
expose-experimental-directivesandshm-stats-fileglobal directives.Add GUIDs to your frontends, backends, and servers. The GUIDs must be unique within your configuration.
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
randominstead ofroundrobin, when not otherwise set with thebalancedirective 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-policynow defaults toperformance, meaning that on systems with a heterogenous mix of efficiency and performance core types, the load balancer will run on only theperformancecores. 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 httpnow setoption abortoncloseby 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 setoption abortonclosein 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-serverdirective unless you declare one in your configuration. Also, after parsing the directive, HAProxy releases the memory associated with it.When using a
use-serverdirective ortrackargument 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
ccargument on abindorserverline.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-reuseis set toneveror 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 |
| An alias for |
| This returns the number of bytes sent to the server. |
| An alias for |
| This returns the number of bytes sent to the client. |
Converters
New converters in this release are:
Converter | Description |
| Converts a binary input sample to a binary string containing eight binary digits per input byte. |
| 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-storeandcrt-listtogether, 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 thecrt-listhas 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
typedargument, 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
-vqfor version,-vqsfor the short version, or-vqbfor the branch.If you've set the
expose-experimental-directivesglobal 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-familythat was introduced in the last version now defaults to the valueauto. This directive lets you disable IPv4 or IPv6 DNS resolution. A value ofautowill 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
nbthreadsto a total number of threads on which HAProxy should run while also declaring athread-groupsdirective 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
userandgroupglobal directives, due to a known limitation in libc. HAProxy will now emit a warning at startup if it detects this. In this case, use theuidandgiddirectives 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-forwardis no longer experimental, so you don't need to setexpose-experimental-directivesto 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-reloadsis now 50.To build the halog utility, run
make install-admininstead ofmake 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
dispatchandoption transparentare deprecated and will emit a warning to replace them if used.Global directives prefixed with
tune.quic.frontendare deprecated. Use the same directives prefixed withtune.quic.feinstead.The
master-workerglobal directive has been deprecated. Use the command-line arguments-Wor-Wsinstead.
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, orlog-forwardsection 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
serverin a backend isn't allowed.When configuring email alerts, you must enable the Lua implementation. If you add a
mailersconfiguration 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 headersconnection,content-length,host, ortransfer-encoding. Overwriting those headers would only cause an invalid request.When declaring an ACL, you can set the match type via the
-mflag 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 inpath_beg -m reg. Is it matching the beginning of the path or using a regular expression?This version renames the
no-quicglobal directive totune.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.
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.