Enabling HTTP/3 in Envoy for Low‑Latency QUIC Traffic
Learn how to add an HTTP/3 listener to Envoy, verify QUIC handshakes, and understand the trade‑offs of using UDP for low‑latency traffic.
10 Feb 2026, 03:50 UTC

Problem: TCP head‑of‑line blocking hurts bursty mobile traffic
When a service receives many short, independent requests over a single TCP connection, a lost packet stalls all subsequent streams until retransmission finishes. This head‑of‑line (HOL) blocking adds latency, especially on lossy or high‑delay networks where mobile clients operate.
Thesis: Envoy’s native HTTP/3 support lets you offload QUIC‑based traffic to the proxy, gaining multiplexed streams without TCP HOL while keeping TLS 1.3 encryption.
How HTTP/3 works in Envoy
Envoy treats HTTP/3 as a first‑class protocol. A listener can declare http3_protocol_options and bind a UDP port. When a client initiates a QUIC handshake, Envoy performs the TLS 1.3 handshake over UDP, then negotiates HTTP/3. If the client does not support QUIC, Envoy falls back to its usual TCP listeners for HTTP/1.1 or HTTP/2.
Worked example: adding an HTTP/3 listener
- Check the binary:
envoy --version(must show ≥ 1.25 and include--with-http3in the build flags). - Create a minimal bootstrap YAML (or JSON) that defines two listeners: one for TCP (fallback) and one for UDP/HTTP/3.
static_resources:
listeners:
- name: listener_http
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: backend_cluster }
http_protocol_options: {}
- name: listener_http3
address:
socket_address: { address: 0.0.0.0, port_value: 8443, protocol: UDP }
filter_chains:
- filters:
- name: envoy.filters.network.quic_listener
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.quic_listener.v3.QuicListener
stat_prefix: ingress_http3
quic_options:
# TLS context shared with TCP listener (omitted for brevity)
# ...
http3_protocol_options: {} # enables HTTP/3 over QUIC
clusters:
- name: backend_cluster
connect_timeout: 0.25s
type: LOGICAL_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: backend_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: 127.0.0.1, port_value: 8081 }
Explanation:
- The TCP listener on port 8080 handles legacy HTTP/1.1/HTTP/2 traffic.
- The UDP listener on port 8443 runs the QUIC listener filter; the empty
http3_protocol_optionsblock tells Envoy to enable HTTP/3. - Both listeners share the same route configuration, so requests are routed to the same backend cluster regardless of the transport.
Verification steps
- Start Envoy with the config:
envoy -c envoy.yaml(requires permission to bind to ports 8080 and 8443; on Linux you can useCAP_NET_BIND_SERVICEor run as root for ports < 1024). - From a client that supports HTTP/3 (e.g., curl ≥ 7.66 with nghttp3), run:
curl --http3 --verbose https://localhost:8443/. Look for the lineUsing HTTP/3in the verbose output. - If the client lacks QUIC support, the same request against port 8080 will succeed using HTTP/1.1 or HTTP/2, demonstrating Envoy’s fallback.
- Check Envoy’s access logs: each entry includes
:request_protocolset to"HTTP/3"for QUIC‑handled requests.
Trade‑offs and limitations
- **Client coverage** – Only clients that implement QUIC (modern browsers, recent curl, mobile SDKs) will benefit. Legacy clients never see the improvement.
- **Network policy** – UDP port 8443 must be allowed through firewalls, NAT, and any middleboxes that block or rate‑limit UDP. In restricted environments you may need to keep the TCP listener as the sole entry point.
- **Operational overhead** – You now maintain two listener configurations and must monitor both TCP and UDP metrics. Envoy’s admin interface provides separate stats for
listener_http3andlistener_http. - **Debugging** – Because QUIC encrypts the payload, traditional TCP tools (tcpdump, Wireshark) only see encrypted packets. Use
sslkeylogoutput or Envoy’s access logs with:request_protocolto verify protocol selection.
Actionable closing
If your service serves short, bursty requests from mobile or lossy networks, enable the UDP listener with http3_protocol_options as shown above. Verify the handshake with a HTTP/3‑capable curl, monitor the :request_protocol field in Envoy’s logs, and ensure your firewall permits the chosen UDP port. When QUIC is unavailable, Envoy will seamlessly fall back to TCP, giving you a safe roll‑out path.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.