HAProxy can load balance QUIC, the protocol that powers HTTP/3, but it’s not as simple as just flipping a switch.

Here’s HAProxy serving HTTP/3 to clients and HTTP/1.1 to backend servers.

frontend http_quic
    bind *:443 ssl crt /etc/ssl/certs/your_domain.pem alpn h3,http/1.1
    mode http
    http-request set-header x-forwarded-proto http
    default_backend http_servers

backend http_servers
    mode http
    balance roundrobin
    server s1 192.168.1.10:80 check
    server s2 192.168.1.11:80 check

This configuration binds to port 443, enabling both the h3 (HTTP/3) and http/1.1 Application-Layer Protocols (ALPN) for TLS negotiation. When a client connects, HAProxy offers both protocols. If the client supports HTTP/3, it will negotiate that. If not, it falls back to HTTP/1.1. The mode http and default_backend directives then route the request to the http_servers backend, which is configured for standard HTTP/1.1 on port 80.

The primary problem HAProxy solves with QUIC is enabling modern, faster web delivery to clients that support it, without requiring immediate upgrades to backend infrastructure. QUIC, built on UDP, offers significant improvements over TCP, including reduced connection establishment latency (0-RTT or 1-RTT), better congestion control, and improved multiplexing that prevents head-of-line blocking at the connection level. By allowing HAProxy to speak HTTP/3 with clients and HTTP/1.1 with existing servers, you get the benefits of QUIC for the client-facing part of your network while maintaining compatibility with your current backend services. It’s a transitionary technology that bridges the gap between legacy and future web protocols.

HAProxy’s QUIC support is implemented as a layer on top of its existing HTTP and TLS capabilities. It leverages the libquic library (or its own internal implementation, depending on the HAProxy version and build) to handle the QUIC handshake and packet framing. When a client initiates a connection and ALPN negotiation selects h3, HAProxy establishes a QUIC connection. It then translates the HTTP/3 frames within the QUIC packets into standard HTTP/1.1 requests that are sent to the backend servers. For responses, it does the reverse, taking HTTP/1.1 responses from the backend and framing them as HTTP/3 for the client. This translation is key to its utility, as it means your backend servers don’t need to understand HTTP/3 at all.

The bind line is where the magic happens for QUIC. bind *:443 ssl crt /etc/ssl/certs/your_domain.pem alpn h3,http/1.1 tells HAProxy to listen on port 443 for SSL/TLS connections. The alpn h3,http/1.1 part is crucial. During the TLS handshake, the client and server negotiate which application-layer protocol to use. By listing h3 first, HAProxy signals that it prefers HTTP/3. If the client also supports h3, they’ll agree to use it. If the client only supports http/1.1, HAProxy will fall back to that. The comma-separated list essentially provides a prioritized list of supported protocols.

The mode http directive ensures that HAProxy operates at the HTTP layer, allowing it to inspect and manipulate HTTP headers. The http-request set-header x-forwarded-proto http is important because the original protocol from the client (QUIC, which carries HTTP/3) is lost when HAProxy forwards the request as HTTP/1.1 to the backend. This header tells the backend server that the original request came over HTTP, even though the direct connection from HAProxy to the backend is plain HTTP/1.1. This is vital for applications that rely on the protocol for logic or logging.

The backend definition backend http_servers is straightforward. mode http again signifies HTTP traffic. balance roundrobin distributes requests. The server lines specify the IP addresses and ports of your actual web servers. Critically, these servers are listening on port 80 (or another standard HTTP port), not QUIC. HAProxy handles the protocol translation.

One aspect often overlooked is how HAProxy manages the UDP sockets required for QUIC. Unlike TCP, which has a single socket per connection, QUIC uses UDP. HAProxy will open and manage multiple UDP sockets on the frontend port (443 in this case) to handle the incoming QUIC traffic. This is transparent to the user for basic setups, but understanding that it’s UDP-based is key if you encounter network-level issues, as UDP is connectionless and firewalls might treat it differently than TCP. Also, ensure your UDP buffer sizes are adequately tuned on the server running HAProxy, as high-volume QUIC traffic can saturate them.

The next thing you’ll likely wrestle with is configuring advanced QUIC features, like connection migration and improved error handling, or optimizing TLS cipher suites specifically for QUIC.

Want structured learning?

Take the full Quic course →