HAProxy doesn’t just enable HTTP/2; it rewrites your HTTP/1.1 requests into HTTP/2 for the backend, and then back to HTTP/1.1 for the client if the client doesn’t support HTTP/2.

Let’s see HAProxy in action, managing a simple frontend and backend.

frontend http_frontend
    bind *:80
    bind *:443 ssl crt /etc/ssl/certs/mycert.pem alpn h2,http/1.1
    default_backend http_backend

backend http_backend
    server app1 192.168.1.10:80 check
    server app2 192.168.1.11:80 check

Here’s what’s happening:

  • frontend http_frontend: This section defines how HAProxy listens for incoming connections.
  • bind *:80: This line tells HAProxy to listen on port 80 for plain HTTP traffic.
  • bind *:443 ssl crt /etc/ssl/certs/mycert.pem alpn h2,http/1.1: This is where the magic for HTTPS and HTTP/2 happens.
    • *:443: Listen on port 443 for HTTPS traffic.
    • ssl crt /etc/ssl/certs/mycert.pem: Enable SSL/TLS and specify the certificate file. You’ll need to replace /etc/ssl/certs/mycert.pem with the actual path to your certificate and private key file (often a combined .pem file).
    • alpn h2,http/1.1: This is the Application-Layer Protocol Negotiation (ALPN) extension for TLS. It tells clients that HAProxy supports both HTTP/2 (h2) and HTTP/1.1 (http/1.1). The order matters: h2 is preferred. When a client connects via HTTPS, it will negotiate which protocol to use based on this list. If the client supports h2, HAProxy will speak HTTP/2 with it.
  • default_backend http_backend: Any traffic hitting this frontend will be directed to the http_backend unless specific rules say otherwise.
  • backend http_backend: This section defines the group of servers that will handle the requests.
  • server app1 192.168.1.10:80 check: Defines a backend server named app1 at IP 192.168.1.10 on port 80. The check directive means HAProxy will periodically ping this server to ensure it’s healthy.
  • server app2 192.168.1.11:80 check: Defines another backend server.

When a client connects to https://yourdomain.com (port 443), it performs a TLS handshake. During this handshake, the client and HAProxy negotiate the application protocol using ALPN. If the client offers h2 and HAProxy supports it (as specified by alpn h2,http/1.1), they will establish an HTTP/2 connection. HAProxy then rewrites the HTTP/2 frames into HTTP/1.1 requests and forwards them to your backend servers. The responses from the backend (which will be HTTP/1.1) are then rewritten back into HTTP/2 frames by HAProxy before being sent to the client.

If the client does not support HTTP/2 or HAProxy’s ALPN list didn’t include h2, they would fall back to http/1.1.

The real power of HAProxy here is its ability to act as a protocol translator. Your backend servers can remain on HTTP/1.1, simplifying their configuration and development, while you can offer the performance benefits of HTTP/2 to modern clients. This is achieved by HAProxy’s internal handling of the protocol negotiation and conversion.

What most people miss is that HAProxy’s HTTP/2 support is primarily for downstream communication (client to HAProxy) and upstream conversion (HAProxy to backend). It doesn’t mandate that your backend servers must speak HTTP/2. This allows for a gradual adoption of HTTP/2 without requiring immediate upgrades of all your application servers.

The next hurdle is understanding how to leverage HTTP/2’s multiplexing and header compression for even finer-grained control.

Want structured learning?

Take the full Haproxy course →