Protocol support
HTTP
Although HAProxy can load balance HTTP requests in TCP mode, in which the connections are opaque and the HTTP messages aren’t inspected or altered, it can also operate in HTTP mode. In HTTP mode, the load balancer can inspect and modify the messages to perform protocol-specific actions. To enable HTTP mode, set the directive mode http in your frontend and backend sections.
Below, we describe features related to distinct versions of the HTTP protocol.
HTTP/3 Jump to heading
HAProxy can send and receive HTTP/3 messages over the QUIC protocol.
While earlier HTTP implementations were transported over TCP, the HTTP/3 protocol is transported over QUIC, a UDP-based, connectionless protocol. To support QUIC, your HAProxy package must bundle a QUIC-compatible TLS library.
- For HAProxy, see the Community Edition packages.
- For HAProxy Enterprise, see the guide Install HAProxy Enterprise on Linux.
- For HAProxy ALOHA 15.0 and newer, it’s installed by default.
HTTP/3 over HTTPS to the client Jump to heading
This section applies to:
- HAProxy 2.7 and newer
- HAProxy Enterprise 2.7r1 and newer
- HAProxy ALOHA 15.0 and newer
To enable HTTP/3 between the load balancer and the client, update your configuration so that your frontend includes the required directives:
- a
binddirective that uses the address prefixquic4@and setsalpn h3. Note that for HAProxy 2.8 / HAProxy Enterprise 2.8r1 / HAProxy ALOHA 15.5 and newer, you don’t need to set thealpnargument, since it defaults toh3. - an
http-response set-headerdirective that sets thealt-svcheader.
haproxyfrontend examplebind :80# Enable HTTPSbind :443 ssl crt ssl.pem# enables HTTP/3 over QUICbind quic4@:443 ssl crt ssl.pem alpn h3# Redirects to HTTPShttp-request redirect scheme https unless { ssl_fc }# 'Alt-Svc' header invites client to switch to the QUIC protocol# Max age (ma) is set to 15 minutes (900 seconds), but# can be increased once verified working as expectedhttp-response set-header alt-svc "h3=\":443\";ma=900;"default_backend webservers
haproxyfrontend examplebind :80# Enable HTTPSbind :443 ssl crt ssl.pem# enables HTTP/3 over QUICbind quic4@:443 ssl crt ssl.pem alpn h3# Redirects to HTTPShttp-request redirect scheme https unless { ssl_fc }# 'Alt-Svc' header invites client to switch to the QUIC protocol# Max age (ma) is set to 15 minutes (900 seconds), but# can be increased once verified working as expectedhttp-response set-header alt-svc "h3=\":443\";ma=900;"default_backend webservers
HTTP/3 over HTTPS to the server Jump to heading
This section applies to:
- HAProxy 3.3 and newer
- HAProxy Enterprise 3.3r1 and newer
- HAProxy ALOHA 18.0 and newer
Experimental feature
This feature is experimental! To use it, add expose-experimental-directives to your global configuration section.
To connect to backend servers with HTTP/3 over QUIC, prefix the server’s address with quic4@ and enable SSL/TLS arguments. Ensure that your backend web server supports HTTP/3 and has it enabled.
haproxybackend serversmode httpserver s1 quic4@192.168.0.10:443 check maxconn 30 ssl verify required ca-file /etc/haproxy/ssl/myca.pem
haproxybackend serversmode httpserver s1 quic4@192.168.0.10:443 check maxconn 30 ssl verify required ca-file /etc/haproxy/ssl/myca.pem
Troubleshoot HTTP/3 over QUIC Jump to heading
Browsers can be strict when it comes to QUIC, and when they encounter an issue, they will silently fall back to using HTTP/2. For instance, they often don’t allow self-signed TLS certificates, and getting verbose error logs from a browser can be difficult.
Try running the QUIC-compatible curl command to test QUIC connections so that you can see the verbose output of the request and response. Run it as a Docker container, as in the following example where we run curl as a container to test HTTP/3 over QUIC for example.com:
nixdocker run -ti --rm alpine/curl-http3 curl --verbose --http3 --silent --head https://example.com
nixdocker run -ti --rm alpine/curl-http3 curl --verbose --http3 --silent --head https://example.com
HTTP/2 Jump to heading
You can load balance HTTP/2 over:
- encrypted HTTPS when OpenSSL 1.0.2 or newer is available on the server
- unencrypted HTTP (known as h2c)
Most browsers support HTTP/2 over HTTPS only, but you may find it useful to enable h2c between backend services (for example, gRPC services).
HTTP/2 over HTTPS to the client Jump to heading
This section applies to:
- HAProxy 1.8 and newer
- HAProxy Enterprise 1.8r1 and newer
- HAProxy ALOHA 10.0 and newer
HTTP/2 is enabled by default between clients and load balancer in HAProxy ALOHA 15.5 / HAProxy Enterprise 2.8r1 and up. You don’t need to specify the alpn extension, because it has a default value of h2,http/1.1 for HTTPS bind lines. Note that ALPN works only for HTTPS bind lines, so HTTP/2 requires HTTPS. Clients that lack support for HTTP/2 will be automatically reverted to HTTP/1.1. The load balancer server must have OpenSSL 1.0.2 or newer.
haproxyfrontend wwwmode httpbind :443 ssl crt /path/to/cert.crtdefault_backend servers
haproxyfrontend wwwmode httpbind :443 ssl crt /path/to/cert.crtdefault_backend servers
For HAProxy ALOHA 15.0 / HAProxy Enterprise 2.7r1 and older, you will need to specify both the extension and protocols:
haproxyfrontend wwwmode httpbind :443 ssl crt /path/to/cert.crt alpn h2,http/1.1default_backend servers
haproxyfrontend wwwmode httpbind :443 ssl crt /path/to/cert.crt alpn h2,http/1.1default_backend servers
HTTP/2 over HTTPS to the server Jump to heading
This section applies to:
- HAProxy 1.9 and newer
- HAProxy Enterprise 1.9r1 and newer
- HAProxy ALOHA 11.0 and newer
To enable HTTP/2 between the load balancer and your backend servers, add the alpn argument to your server or default-server lines:
haproxybackend serversmode httpserver s1 192.168.0.10:443 ssl alpn h2,http/1.1server s2 192.168.0.11:443 ssl alpn h2,http/1.1
haproxybackend serversmode httpserver s1 192.168.0.10:443 ssl alpn h2,http/1.1server s2 192.168.0.11:443 ssl alpn h2,http/1.1
This announces to the servers that the load balancer, acting as a client, supports HTTP/2. The servers must also support it.
HTTP/2 over HTTP (h2c) to the client Jump to heading
This section applies to:
- HAProxy 1.9 and newer
- HAProxy Enterprise 1.9r1 and newer
- HAProxy ALOHA 11.0 and newer
To enable HTTP/2 between clients and the load balancer without using TLS, use the proto argument to announce support for it. This method doesn’t allow you to support multiple versions of HTTP simultaneously.
haproxyfrontend wwwmode httpbind :80 proto h2default_backend servers
haproxyfrontend wwwmode httpbind :80 proto h2default_backend servers
HTTP/2 over HTTP (h2c) to the server Jump to heading
This section applies to:
- HAProxy 1.9 and newer
- HAProxy Enterprise 1.9r1 and newer
- HAProxy ALOHA 11.0 and newer
To enable HTTP/2 between the load balancer and your backend servers, add the proto argument to your server or default-server lines:
haproxybackend serversmode httpserver s1 192.168.0.10:80 proto h2server s2 192.168.0.11:80 proto h2
haproxybackend serversmode httpserver s1 192.168.0.10:80 proto h2server s2 192.168.0.11:80 proto h2
Adjust the HTTP/2 initial window size Jump to heading
When you expect large file uploads over a network with moderately high latency, you may experience slow upload speeds. You can increase the HTTP/2 Flow Control window size to allow the load balancer to buffer more data. Set tune.h2.initial-window-size in the global section to the number of bytes the client can upload before waiting for an acknowledgement from the load balancer. For example, you could set a high value like 1048576.
Enable an idleness ping Jump to heading
This section applies to:
- HAProxy 3.2 and newer
- HAProxy Enterprise 3.2r1 and newer
- HAProxy ALOHA 17.5 and newer
To more efficiently close any idle HTTP/2 connections, you can add an idle connection check.
-
For HTTP/2 to the client, add
idle-pingto thebindline. It sets an interval, such as 10 seconds in this example:haproxyfrontend wwwmode httpbind :443 ssl crt /path/to/cert.crt idle-ping 10sdefault_backend servershaproxyfrontend wwwmode httpbind :443 ssl crt /path/to/cert.crt idle-ping 10sdefault_backend servers -
For HTTP/2 to the server, add
idle-pingto theserverline. It sets an interval, such as 10 seconds in this example:haproxybackend serversmode httpserver s1 192.168.0.10:443 ssl alpn h2,http/1.1 idle-ping 10sserver s2 192.168.0.11:443 ssl alpn h2,http/1.1 idle-ping 10shaproxybackend serversmode httpserver s1 192.168.0.10:443 ssl alpn h2,http/1.1 idle-ping 10sserver s2 192.168.0.11:443 ssl alpn h2,http/1.1 idle-ping 10s
Handle glitches Jump to heading
This section applies to:
- HAProxy 3.0 and newer
- HAProxy Enterprise 3.0r1 and newer
- HAProxy ALOHA 16.5 and newer
HTTP messages that can cause problems in the infrastructure are called glitches. They can indicate a variety of issues such as excessive protocol violations, malfunctioning clients or servers, premature connection aborts, overly large requests, or malicious attacks.
The load balancer provides several tools to help you handle glitches.
Threshold tunable parameters
The load balancer provides global parameters allowing you to configure how it handles glitchy connections.
We recommend that you use these tunable parameters to control glitchy connections rather than other methods, such as using http-request deny.
There is a threshold parameter for each combination of protocol and proxy:
- HTML/2 frontend connections:
tune.h2.fe.glitches-threshold <number> - HTML/2 backend connections:
tune.h2.be.glitches-threshold <number> - HTML/3 QUIC frontend connections:
tune.quic.fe.sec.glitches-threshold <number> - HTML/3 QUIC backend connections:
tune.quic.be.sec.glitches-threshold <number>
When the total number of glitches on a connection reaches the threshold number, the load balancer closes it. The default threshold value is zero (never close). Occasional glitches are normal, so if you set a threshold, set it in the hundreds or thousands to avoid disrupting normal traffic.
If you set thresholds, also consider setting the tune.glitches.kill.cpu-usage parameter to avoid closing glitchy connections that do not impact CPU usage. In environments where very long connections often behave badly without causing any performance impact, it might be desirable to tolerate misbehavior and to close such connections only when the CPU is getting busy. Establishing a connection is a CPU-intensive operation, which is why there is benefit to leaving these connections open.
The following enhancement applies to:
- HAProxy 3.4 and newer
- HAProxy ALOHA 18.5 and newer
When closing connections that violate the specified threshold, the load balancer attempts a graceful close strategy before performing a hard close.
When a connection reaches 75% of the threshold, the load balancer attempts a graceful close by advertising GOAWAY for a future stream. This action ensures that a slightly non-compliant client will have the opportunity to create a new connection and continue to work unaffected without triggering the hard close and thus risking an interruption of ongoing transfers.
Fetches
To fetch the number of glitchy requests and responses, use the fetch methods fc_glitches and bc_glitches.
-
The
fc_glitchesfetch returns the number of glitches counted on the frontend connection. Ideally, the value should be zero. A sudden jump in glitches may indicate an anomaly. If a connection has hundreds of glitches or more, the client could be malicious. -
The
bc_glitchesfetch returns the number of glitches counted on the backend connection. Ideally, the value should be zero. A sudden jump in glitches may indicate an anomaly such as a malfunctioning backend server.
Stick tables
To track glitches with a stick table, use these data types:
glitch_cnt: The cumulative number of glitches reported on a frontend connection.glitch_rate: The average frontend glitch rate over the specified period.
Use these fetches to get data from stick tables:
-
sc_glitch_cnt(<ctr>[,<table>]): Returns the cumulative number of frontend glitches that were observed on connections associated with the currently tracked counters. See alsofc_glitchesfor the number affecting the current connection,src_glitch_cntto look them up per source, andsc_glitch_ratefor the event rate measurements. -
sc_glitch_rate(<ctr>[,<table>]): Returns the average rate at which frontend glitches were observed for the currently tracked counters, measured in amount of events over the period configured in the table. See alsotable_glitch_rateandsc_glitch_cnt.
Use these converters with stick tables:
-
table_glitch_cnt([<table>]): Uses the input sample to perform a look up in the current proxy’s stick-table or in the designated stick-table. Returns the cumulative number of frontend glitches associated with the input sample in the designated table. See also thesc_glitch_cntsample fetch keyword andfc_glitchesfor the value measured on the current front connection. -
table_glitch_rate([<table>]): Uses the input sample to perform a look up in the current proxy’s stick-table or in the designated stick-table. Returns the average frontend glitch rate associated with the input sample in the designated table. See also thesc_glitch_ratesample fetch keyword. -
src_glitch_cnt([<table>]): Same as thetable_glitch_cntconverter with key set to the incoming connection’s source address. Equivalent tosrc,table_glitch_cnt([<table>]). -
src_glitch_rate([<table>]): Same as thetable_glitch_rateconverter with key set to the incoming connection’s source address. Equivalent tosrc,table_glitch_rate([<table>]).
Example: log glitch counts per client IP address Jump to heading
In this example, we use a stick table to track glitches by client IP. Then we log the number of glitches per connection, the cumulative glitch count, and the glitch rate.
- For each client, the stick table will store the cumulative glitches (
glitch_cnt) and glitch rate over a 1-minute moving window (glitch_rate(1m)). - We need to use
tcp-request connectionto update the stick table; otherwise, when a bad request comes through, the load balancer drops it without further processing. - Our log format contains:
src=%ci: The client IPsrc=%ci: The client IPfc_glitches=%[fc_glitches]: The number of glitches recorded for the frontend connection.sc0_glitch_cnt=%[sc0_glitch_cnt]: The total accumulated glitches stored in the stick-table for this IP.sc0_glitch_rate=%[sc0_glitch_rate]: The glitch frequency for this IP over the 1-minute window.
Here’s the configuration for our stick table and log format:
haproxyfrontend www...stick-table type ip size 1m expire 30m store glitch_cnt,glitch_rate(1m)tcp-request connection track-sc0 srclog-format "src=%ci fc_glitches=%[fc_glitches] sc0_glitch_cnt=%[sc0_glitch_cnt] sc0_glitch_rate=%[sc0_glitch_rate]"
haproxyfrontend www...stick-table type ip size 1m expire 30m store glitch_cnt,glitch_rate(1m)tcp-request connection track-sc0 srclog-format "src=%ci fc_glitches=%[fc_glitches] sc0_glitch_cnt=%[sc0_glitch_cnt] sc0_glitch_rate=%[sc0_glitch_rate]"
For our example, we’ll send a request having the invalid HTTP method BAD_METHOD:
nixcurl -X "BAD_METHOD" -v http://localhost:80
nixcurl -X "BAD_METHOD" -v http://localhost:80
outputtext* Host localhost:80 was resolved.* IPv6: ::1* IPv4: 127.0.0.1* Trying [::1]:80...* Connected to localhost (::1) port 80> BAD_METHOD / HTTP/1.1> Host: localhost> User-Agent: curl/8.5.0> Accept: */*>< HTTP/1.1 400 Bad request< Content-length: 90< Cache-Control: no-cache< Connection: close< Content-Type: text/html<<html><body><h1>400 Bad request</h1>Your browser sent an invalid request.</body></html>* Closing connection
outputtext* Host localhost:80 was resolved.* IPv6: ::1* IPv4: 127.0.0.1* Trying [::1]:80...* Connected to localhost (::1) port 80> BAD_METHOD / HTTP/1.1> Host: localhost> User-Agent: curl/8.5.0> Accept: */*>< HTTP/1.1 400 Bad request< Content-length: 90< Cache-Control: no-cache< Connection: close< Content-Type: text/html<<html><body><h1>400 Bad request</h1>Your browser sent an invalid request.</body></html>* Closing connection
The counters increase and are logged with each request. Here’s the log after 5 bad requests from the host at IP 172.16.0.1:
logtexthaproxy-1 | src=172.16.0.1 fc_glitches=1 sc0_glitch_cnt=0 sc0_glitch_rate=0haproxy-1 | src=172.16.0.1 fc_glitches=1 sc0_glitch_cnt=1 sc0_glitch_rate=1haproxy-1 | src=172.16.0.1 fc_glitches=1 sc0_glitch_cnt=2 sc0_glitch_rate=2haproxy-1 | src=172.16.0.1 fc_glitches=1 sc0_glitch_cnt=3 sc0_glitch_rate=3haproxy-1 | src=172.16.0.1 fc_glitches=1 sc0_glitch_cnt=4 sc0_glitch_rate=4
logtexthaproxy-1 | src=172.16.0.1 fc_glitches=1 sc0_glitch_cnt=0 sc0_glitch_rate=0haproxy-1 | src=172.16.0.1 fc_glitches=1 sc0_glitch_cnt=1 sc0_glitch_rate=1haproxy-1 | src=172.16.0.1 fc_glitches=1 sc0_glitch_cnt=2 sc0_glitch_rate=2haproxy-1 | src=172.16.0.1 fc_glitches=1 sc0_glitch_cnt=3 sc0_glitch_rate=3haproxy-1 | src=172.16.0.1 fc_glitches=1 sc0_glitch_cnt=4 sc0_glitch_rate=4
See also Jump to heading
- To enable the TLS ALPN extension and a protocol list for the
binddirective, see bind - alpn. - To force a protocol for the
binddirective, see bind - proto. - To enable the TLS ALPN extension and a protocol list for the
serverdirective, see server - alpn. - To force a protocol for the
serverdirective, see server - proto. - To set the default value for the HTTP/2 initial window size, see tune.h2.initial-window-size.
- To set the glitch threshold for HTML/2 frontend connections, see tune.h2.fe.glitches-threshold.
- To set the glitch threshold for HTML/2 backend connections, see tune.h2.be.glitches-threshold.
- To set the glitch threshold for HTML/3 QUIC frontend connections, see tune.quic.fe.sec.glitches-threshold.
- To set the glitch threshold for HTML/3 QUIC backend connections, see tune.quic.be.sec.glitches-threshold.