Configure HTTP/3 QUIC Between Client and APISIX
HTTP/3 is the third major version of the Hypertext Transfer Protocol (HTTP). Unlike its predecessors which rely on TCP, HTTP/3 is based on QUIC (Quick UDP Internet Connections) protocol. It brings several benefits that collectively result in reduced latency and improved performance:
- enabling seamless transition between different network connections, such as switching from Wi-Fi to mobile data.
- eliminating head-of-line blocking, so that a lost packet does not block all streams.
- negotiating TLS versions at the same time as the TLS handshakes, allowing for faster connections.
- providing encryption by default, ensuring that all data transmitted over an HTTP/3 connection is protected and confidential.
- providing zero round-trip time (0-RTT) when communicating with servers that clients have already established connections to.
APISIX currently supports HTTP/3 connections between downstream clients and APISIX. HTTP/3 connections with upstream services are not yet supported.
This feature is currently experimental and not recommended for production use.
This guide will show you how to configure APISIX to enable HTTP/3 connections between client and APISIX.
Prerequisite(s)
- Install Docker.
- Install static-curl or other curl that has HTTP/3 support.
- Follow the Getting Started tutorial to start a new APISIX instance in Docker or on Kubernetes.
- Install jq to encode the PEM files as JSON strings.
- If you use the Admin API examples and authentication is enabled, export an admin-role key as
ADMIN_API_KEY. Configure the key underdeployment.admin.admin_key. The Docker quickstart disables authentication for local evaluation; keep it enabled in production.
Enable HTTP/3 in APISIX
Copy the complete active config.yaml to the host and keep a backup:
docker cp apisix-quickstart:/usr/local/apisix/conf/config.yaml ./config.yaml
cp ./config.yaml ./config.yaml.backup
In the local config.yaml, update the listener for port 9443 under apisix.ssl.listen; if that listener does not exist, add it to the existing list. The following is a fragment, not a replacement file:
apisix:
ssl:
listen:
- port: 9443
enable_http3: true
Keep the existing Admin API authentication, allowlist, etcd, and plugin settings. Do not add a second apisix or ssl mapping. Copy the candidate file into the container, then validate it and reload APISIX only if validation succeeds:
docker cp ./config.yaml apisix-quickstart:/usr/local/apisix/conf/config.yaml
docker exec apisix-quickstart apisix test && \
docker exec apisix-quickstart apisix reload
If validation fails, restore the backup before making another change:
docker cp ./config.yaml.backup apisix-quickstart:/usr/local/apisix/conf/config.yaml
Keep the backup until HTTP/3 verification succeeds.
Generate Certificates and Keys
HTTP/3 requires TLS. You can purchase the certificates or self-generate them, whichever is applicable.
To self-generate, first generate the certificate authority (CA) key and certificate:
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 36500 -sha256 \
-key ca.key \
-out ca.crt \
-subj "/CN=MyTestCA" \
-extensions v3_ca \
-config <(printf "[req]\ndistinguished_name=req\n[v3_ca]\nbasicConstraints=critical,CA:TRUE\nkeyUsage=critical,keyCertSign,cRLSign\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid:always,issuer")
Next, generate the key and certificate signing request (CSR) for APISIX:
openssl genrsa -out server.key 2048
openssl req -new -sha256 \
-key server.key \
-out server.csr \
-subj "/CN=test.com"
Sign the server CSR with the CA certificate. The subject alternative name (SAN) makes the certificate valid for the DNS name test.com:
openssl x509 -req -days 36500 -sha256 \
-in server.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt \
-extensions v3_req \
-extfile <(printf "[v3_req]\nbasicConstraints=CA:FALSE\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth\nsubjectAltName=DNS:test.com")
Configure HTTPS
Create the SSL object with an SNI that matches the certificate's test.com DNS name. jq reads the certificate and private key files and encodes their newlines as valid JSON:
jq -n --rawfile cert server.crt --rawfile key server.key \
'{id: "quickstart-tls-client-ssl", sni: "test.com", cert: $cert, key: $key}' \
| curl -i "http://127.0.0.1:9180/apisix/admin/ssls" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @-
Create a Route in APISIX
Create a sample route to httpbin.org:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id":"httpbin-route",
"uri":"/get",
"upstream": {
"type":"roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Verify HTTP/3 Connections between Client and APISIX
Send a request to the route. --cacert verifies the APISIX certificate chain, and --resolve connects test.com to 127.0.0.1 without disabling hostname verification:
curl -v --http3-only --cacert ca.crt \
--noproxy test.com \
--resolve "test.com:9443:127.0.0.1" \
"https://test.com:9443/get"
You should receive an HTTP/3 200 response similar to the following:
* subjectAltName: host "test.com" matched cert's "test.com"
* SSL certificate verify ok.
* using HTTP/3
< HTTP/3 200
The exact transcript depends on the curl TLS backend. Verify that the output confirms certificate verification and that curl used HTTP/3.
Next Steps
You have learned how to configure HTTP/3 between client and APISIX. HTTP/3 connections with upstream services are not yet supported and any contribution is welcome.