đź“… Updated: February 18, 2026 (Originally published: November 6, 2022)
Enabling NGINX HTTP3 on your server delivers faster page loads through QUIC’s UDP-based transport. HTTP/3 reduces network latency, eliminates head-of-line blocking, and supports connection migration for mobile users. This guide shows you how to install NGINX with HTTP3 support on Rocky Linux, AlmaLinux, CentOS, RHEL, and Fedora.
What Is HTTP/3 and Why Use It?
HTTP/3 is the third major version of the Hypertext Transfer Protocol. Unlike HTTP/1.1 and HTTP/2 which use TCP, HTTP/3 uses QUIC—a transport protocol built on UDP. This architectural change provides several benefits:
- Faster connection establishment: QUIC combines the TLS handshake with connection setup, reducing round trips
- No head-of-line blocking: Lost packets don’t block other streams, unlike TCP
- Connection migration: Mobile users maintain connections when switching networks
- Better performance on lossy networks: Packet loss affects only individual streams
Most modern browsers support HTTP/3, including Chrome, Firefox, Safari, and Edge. When you enable NGINX HTTP3, browsers automatically negotiate the fastest available protocol.
Browser Support for HTTP/3
As of 2025, HTTP/3 enjoys widespread browser support. Chrome enabled HTTP/3 by default since version 87, Firefox since version 88, and Safari since version 14. This means over 95% of global web users can benefit from HTTP/3 when your server supports it. Older browsers gracefully fall back to HTTP/2 or HTTP/1.1, ensuring compatibility for all visitors.
HTTP/3 vs HTTP/2 Performance
When should you expect noticeable improvements from HTTP/3? The performance gains depend on network conditions:
High-latency connections benefit most from HTTP/3. QUIC’s 0-RTT connection establishment eliminates the multiple round trips TCP requires. Users on satellite internet or distant geographic locations see faster page loads.
Lossy networks (mobile, WiFi) show significant improvement. With HTTP/2 over TCP, a single lost packet blocks all streams. HTTP/3’s independent streams mean packet loss affects only the affected stream.
Low-latency, reliable connections see minimal improvement. If your users are on fiber connections with <10ms latency, HTTP/2 and HTTP/3 perform similarly.
For most websites, enabling HTTP/3 provides a measurable performance boost for mobile users while maintaining compatibility with older clients through automatic protocol negotiation.
NGINX HTTP3 Packages by GetPageSpeed
With the GetPageSpeed repository, you can quickly install NGINX with full QUIC protocol support. GetPageSpeed NGINX QUIC packages are based on QuicTLS—a special OpenSSL version maintained by Akamai and Microsoft. QuicTLS is a better option compared to BoringSSL because it supports OCSP stapling, just like regular OpenSSL.
Installation is free for Fedora Linux. However, RHEL-based operating systems like CentOS, Rocky Linux, and Amazon Linux require a subscription.
Supported operating systems:
- Amazon Linux 2
- CentOS/RHEL 7
- CentOS/RHEL 8 and clones (Rocky Linux, AlmaLinux)
- CentOS/RHEL 9 and clones (Rocky Linux, AlmaLinux)
- RHEL 10 and clones (Rocky Linux, AlmaLinux)
- Fedora Linux (last two releases)
No matter which supported operating system you use, installation involves:
- Install the GetPageSpeed release package (and subscribe, unless you use Fedora Linux)
- Install the
nginxpackage
Install NGINX QUIC in CentOS/RHEL 7 and Amazon Linux 2
sudo yum -y install https://extras.getpagespeed.com/release-latest.rpm
sudo yum -y install epel-release
sudo yum -y install nginx
If you want to install any of the NGINX Extras module packages like PageSpeed or Brotli:
sudo yum -y install nginx-module-brotli
Don’t forget to follow the instructions for enabling and configuring the respective module.
Install NGINX with HTTP3 Support in CentOS/RHEL/Rocky Linux 8, 9, 10, or Fedora
sudo dnf -y install https://extras.getpagespeed.com/release-latest.rpm dnf-plugins-core
sudo dnf -y install nginx
Likewise, if you want to install any of the NGINX Extras module packages:
sudo dnf -y install nginx-module-brotli
Enable NGINX HTTP3 for Your Websites
Some headers must be explicitly set for HTTP/3 support:
Alt-Svc: h3=":443"; ma=2592000; persist=1advertises that HTTP/3 is available on port 443 and instructs browsers to remember this for 30 daysQUIC-Status: $http3serves as a troubleshooting header showingh3orhqwhen QUIC is working
It is best to use the more_set_headers directive from the headers-more module. Install it with yum -y install nginx-module-headers-more, then add the following at the top of nginx.conf:
load_module modules/ngx_http_headers_more_filter_module.so;
The NGINX HTTP3 configuration is straightforward. You need to add a new listen directive for NGINX to listen on the UDP port:
server {
listen 443 ssl; # TCP listener for HTTP/1.1
listen 443 quic reuseport; # UDP listener for QUIC+HTTP/3
ssl_protocols TLSv1.3; # QUIC requires TLS 1.3
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
http2 on;
http3 on;
more_set_headers 'Alt-Svc: h3=":443"; ma=2592000; persist=1';
more_set_headers 'QUIC-Status: $http3';
}
Note that the reuseport flag can be specified only once per listening port. Set it only for a single server that you designate as the default_server:
server {
listen 443 ssl default_server;
listen 443 quic reuseport default_server;
server_name example.com;
# ...
}
server {
listen 443 ssl;
listen 443 quic;
server_name example.org;
# ...
}
For hosting multiple HTTPS domains with HTTP/3, see our complete NGINX virtual host guide.
If you use IPv6 for your domain, add listeners for IPv6 as well:
listen [::]:443 ssl; # IPv6 TCP listener for HTTP/1.1
listen [::]:443 quic reuseport; # IPv6 UDP listener for QUIC+HTTP/3
Remember that reuseport can be specified once per port, so put it only under a single server with the default_server marker.
The $http_host Problem over HTTP/3
Stock NGINX has a bug: the $http_host variable is empty over HTTP/3. In HTTP/1.1, clients send a literal Host: header. In HTTP/2, NGINX synthesizes one from the :authority pseudo-header. But in HTTP/3, this synthesis is missing — $http_host evaluates to nothing.
This breaks PHP-FPM ($_SERVER['HTTP_HOST'] is empty), reverse proxy configs using proxy_set_header Host $http_host, access logs, and Lua/njs scripts. For a deep dive into the root cause and source code analysis, see NGINX http3 http_host Is Empty — Here’s the Fix.
nginx-mod fixes this at the protocol layer — it creates a synthetic Host header from :authority in HTTP/3, just like HTTP/2 does. No config workarounds needed. $http_host just works across all protocols.
nginx-mod shipped this fix in September 2025, four months before upstream even had a partial workaround. And it’s not just this fix — nginx-mod includes kTLS offload, dynamic TLS records, full HPACK encoding, health checks, and much more. It’s a drop-in replacement for stock NGINX.
To switch to nginx-mod:
sudo dnf config-manager --disable getpagespeed-extras-mainline
sudo dnf config-manager --enable getpagespeed-extras-nginx-mod
sudo dnf -y install nginx
Distribution-Specific Settings
Some QUIC settings enhance protocol performance. Whether they work depends on your kernel version.
quic_bpf on;
On systems with Linux kernel 5.7 and above (Rocky Linux 9+), enable quic_bpf in the main context (at the top of nginx.conf, before any blocks):
quic_bpf on;
user nginx;
worker_processes auto;
# ...
This enables routing of QUIC packets and supports connection migration.
quic_gso on;
On systems with Linux kernel 4.18 and above (Rocky Linux 8+), enable quic_gso in the http or server context:
http {
quic_gso on;
# ...
}
This enables sending in optimized batch mode using segmentation offloading.
Increase UDP Buffer Sizes
QUIC runs over UDP, and the default Linux UDP buffer sizes are far too small for production HTTP/3 workloads. On most distributions, net.core.rmem_max defaults to just 212,992 bytes (~208 KB).
When the kernel’s UDP receive buffer fills up, incoming packets are silently dropped. When the send buffer fills up, NGINX’s QUIC implementation falls back to a 10ms retry delay (NGX_QUIC_SOCKET_RETRY_DELAY). Both degrade performance under concurrent connections.
The widely recommended buffer size for QUIC workloads is 7.5 MB (7,500,000 bytes), a value established by the quic-go project and adopted across the QUIC ecosystem. Recent Linux kernels (6.x) raised the built-in default to 4 MB, acknowledging the old 208 KB limit was inadequate — but 4 MB may still be insufficient under heavy load.
Create /etc/sysctl.d/99-quic.conf:
# Increase UDP buffers for QUIC (HTTP/3) performance
net.core.rmem_max = 7500000
net.core.wmem_max = 7500000
net.core.rmem_default = 7500000
net.core.wmem_default = 7500000
Apply immediately:
sudo sysctl -p /etc/sysctl.d/99-quic.conf
Why all four parameters? NGINX does not call setsockopt() on its QUIC listener socket by default, so the socket inherits rmem_default / wmem_default. The _max values must also be raised because they cap what any application can request — including NGINX when you use listen 443 quic rcvbuf=7m sndbuf=7m; in its configuration.
Persistent QUIC Host Key
By default, NGINX generates a random QUIC key on each reload. This invalidates previously issued address-validation and stateless-reset tokens. Our packages create a persistent key at /etc/nginx/quic.key so tokens remain valid across reloads and restarts.
Add this directive in the http context:
http {
quic_host_key /etc/nginx/quic.key;
}
Other Settings
Set quic_retry on; in security-sensitive applications. If you anticipate attacks like brute-forcing or DDoS attempts, this directive ensures all traffic comes from legitimate IPs.
SELinux Notes
Since NGINX now listens on a privileged UDP port not in the default HTTP context, NGINX would fail to start:
nginx: [emerg] bind() to 0.0.0.0:443 failed (13: Permission denied)
Add UDP port 443 to the http_port_t context:
semanage port -a -t http_port_t -p udp 443
Adjust FirewallD
FirewallD includes predefined service definitions, but HTTPS currently supports TCP only. With HTTP/3 you must explicitly allow UDP connections over port 443.
# UDP connectivity for HTTP/3:
firewall-cmd --permanent --add-service=http3
# TCP connectivity for HTTP/1.1 and HTTP/2:
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
In older distributions without the http3 service definition, use:
firewall-cmd --permanent --add-port=443/udp
Add DNS HTTPS Records for Instant HTTP/3
The Alt-Svc header tells browsers that HTTP/3 is available, but it has a limitation: the browser must first connect via HTTP/2 to receive the header, then reconnect over QUIC on the next request. This means HTTP/3 never works on the first visit.
Safari takes this further — it prefers DNS-based QUIC discovery over Alt-Svc headers. Without a DNS HTTPS record, Safari may never upgrade to HTTP/3 at all, even after multiple visits.
The solution is to add a DNS HTTPS record (type 65, defined in RFC 9460). This record advertises HTTP/3 support at the DNS level, allowing browsers to establish a QUIC connection on the very first visit — no Alt-Svc round-trip required.
Cloudflare (Proxied Domains)
If your domain is proxied through Cloudflare (orange cloud icon), no action is needed. Cloudflare automatically generates HTTPS records for proxied domains when HTTP/3 is enabled in your Cloudflare dashboard under Speed > Optimization > Protocol Optimization.
Verify with:
dig +short example.com HTTPS
You should see a response like:
1 . alpn="h3,h2" ipv4hint=104.21.16.38,172.67.166.21
Cloudflare (DNS-Only Domains)
For DNS-only (grey cloud) domains where Cloudflare only provides DNS and your origin handles HTTPS directly:
- Go to your Cloudflare dashboard > DNS > Records
- Click Add record
- Fill in the fields:
| Field | Value |
|---|---|
| Type | HTTPS |
| Name | @ (for apex domain) |
| Priority | 1 |
| Target | . |
| Value | alpn="h3,h2" |
Repeat for www (or any other subdomain serving HTTP/3)
You can also add the records via the Cloudflare API:
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "HTTPS",
"name": "@",
"data": {
"priority": 1,
"target": ".",
"value": "alpn=\"h3,h2\""
},
"ttl": 3600
}'
Other DNS Providers
Most DNS providers now support HTTPS records. In your provider’s dashboard, create a record with type HTTPS (or type 65). In BIND zone file syntax:
example.com. IN HTTPS 1 . alpn="h3,h2"
www.example.com. IN HTTPS 1 . alpn="h3,h2"
The target . means “use the same hostname” (ServiceMode). The alpn parameter lists supported protocols in preference order — h3 (HTTP/3) first, then h2 (HTTP/2) as fallback.
Verifying DNS HTTPS Records
Check that your records are live:
dig example.com HTTPS +short
Expected output:
1 . alpn="h3,h2"
If dig on your system doesn’t support the HTTPS type, use the numeric form:
dig example.com TYPE65 +short
Why this matters: Research by APNIC found that about 24% of Safari clients fail to use QUIC without DNS HTTPS records, even when Alt-Svc headers are present. Adding these records ensures all browsers — including Safari — can negotiate HTTP/3 immediately.
Note that Alt-Svc headers remain important as a fallback for DNS resolvers that don’t support HTTPS records. Keep both mechanisms configured for maximum compatibility.
Verifying NGINX HTTP3 Is Working
After configuring NGINX HTTP3, verify it works correctly.
Using Browser DevTools
- Open your site in Chrome or Firefox
- Open Developer Tools (F12)
- Go to the Network tab
- Reload the page
- Right-click the column headers and enable “Protocol”
- Look for “h3” in the Protocol column
Using curl
If your curl version supports HTTP/3 (requires curl 7.66+ with nghttp3):
curl --http3 -I https://example.com
A successful response shows the HTTP/3 protocol in use.
Online Testing Tools
Several websites test HTTP/3 support:
- HTTP/3 Check – Enter your URL to verify HTTP/3
- Browser console: Type
performance.getEntriesByType('resource')and check thenextHopProtocolproperty
Troubleshooting NGINX HTTP3 Issues
If NGINX HTTP3 is not working, check these common issues:
Firewall Blocking UDP 443
Verify the firewall allows UDP traffic:
firewall-cmd --list-all | grep 443
You should see both https (TCP) and http3 (UDP) services listed.
SELinux Denials
Check for SELinux denials:
ausearch -m avc -ts recent | grep nginx
If you see denials related to UDP port 443, run the semanage command from the SELinux section above.
Certificate Issues
QUIC requires TLS 1.3. Ensure your certificate is valid and your configuration includes:
ssl_protocols TLSv1.3;
Browser Not Negotiating HTTP/3
Browsers may not use HTTP/3 on first visit when relying solely on Alt-Svc headers. Add DNS HTTPS records (see section above) so browsers can negotiate HTTP/3 immediately. If testing without DNS records, reload the page a second time after the initial visit.
Safari Not Using HTTP/3
Safari prefers DNS-based QUIC discovery. If Safari shows HTTP/2 while Chrome shows HTTP/3:
- Add DNS HTTPS records with
alpn="h3,h2"— this is the primary fix - Check iCloud Private Relay — when enabled, Safari routes traffic through Apple’s proxy servers, forcing HTTP/2
- Verify system QUIC setting — on macOS, run
defaults read /Library/Preferences/com.apple.networkd enable_quic(should return1) - Check QUIC racing — macOS may have QUIC racing disabled via Apple’s remote configuration. Run
defaults read /Library/Preferences/com.apple.networkd disable_quic_race— if it returns1, QUIC is disabled. Fix withsudo defaults write /Library/Preferences/com.apple.networkd disable_quic_race -int 0and reboot
Conclusion
Enabling NGINX HTTP3 improves website performance, especially for users on mobile networks or high-latency connections. The QUIC protocol’s UDP foundation eliminates head-of-line blocking and supports seamless connection migration.
Key steps to enable NGINX HTTP3:
- Install NGINX with QUIC support from GetPageSpeed repository
- Add
listen 443 quicdirective to your server blocks - Configure SELinux to allow UDP port 443
- Open UDP port 443 in FirewallD
- Increase UDP buffer sizes via sysctl for production workloads
- Add DNS HTTPS records for instant HTTP/3 in all browsers
- Set the
Alt-Svcheader to advertise HTTP/3 availability - Verify with browser DevTools or curl
For production deployments, also configure quic_host_key for persistent tokens and consider quic_retry on for additional security.
For the best HTTP/3 experience, consider switching to nginx-mod — it fixes protocol-level bugs like the $http_host issue, adds performance features like kTLS and dynamic TLS records, and is a drop-in replacement for stock NGINX.

