HTTP/3 QUIC Configuration
HTTP/3 is the latest HTTP specification built on top of QUIC (Quick UDP Internet Connections), a modern transport layer protocol offering significant performance improvements over TCP-based HTTP/2. QUIC provides faster connection establishment, improved congestion control, connection migration, and resilience to packet loss. This guide covers configuring HTTP/3 support in Nginx and Caddy, UDP port configuration, Alt-Svc header implementation, certificate setup, browser support, and testing strategies.
Table of Contents
- HTTP/3 and QUIC Overview
- System Requirements
- Nginx QUIC Configuration
- Caddy HTTP/3 Configuration
- UDP Port Configuration
- Alt-Svc Header Setup
- Certificate Management
- Browser Support
- Performance Testing
- Troubleshooting
HTTP/3 and QUIC Overview
HTTP/3 advantages over HTTP/2:
- Faster Connection Setup: 0-RTT handshake enables instant requests
- Connection Migration: Survives network changes (WiFi to cellular)
- Multiplexing: Better handling of packet loss
- Head-of-Line Blocking: Eliminated, independent stream loss handling
- UDP-Based: Lower latency, avoids TCP retransmission delays
QUIC protocol features:
- Transport layer encryption (TLS 1.3 integrated)
- Connection identifiers enabling stateless load balancing
- Congestion control algorithms
- Forward error correction
Deployment considerations:
- Not all networks support UDP port 443 (firewalls, ISPs)
- Fallback to HTTP/2 essential
- Additional CPU overhead for packet processing
- Improved mobile experience
System Requirements
Ensure your infrastructure supports HTTP/3:
- Linux kernel 4.20+ with UDP support
- Nginx with BoringSSL or LibreSSL (for quic module)
- Or use Caddy (native HTTP/3 support)
- TLS 1.3 certificate
- UDP port 443 accessible (firewall rules)
- 512 MB+ RAM for connection tracking
- Modern CPUs for cryptographic operations
Nginx QUIC Configuration
Nginx requires compilation with QUIC module and BoringSSL. Pre-built binaries with QUIC may be available.
Build Nginx with QUIC support:
# Clone Nginx source
cd /tmp
git clone https://github.com/nginx/nginx.git
cd nginx
git submodule update --init
# Clone dependencies
git clone https://github.com/google/boringssl
cd boringssl
mkdir build
cd build
cmake ..
make
cd ../..
# Configure Nginx with QUIC
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/modules \
--with-http_v3_module \
--with-openssl=./boringssl \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_gzip_static_module
make
sudo make install
Configure Nginx for HTTP/3:
http {
# Enable HTTP/3
http3_max_concurrent_streams 128;
http3_max_field_size 16k;
http3_max_header_size 32k;
quic_bpf on;
quic_gso on;
upstream backend {
server 192.168.1.100:8000;
server 192.168.1.101:8000;
keepalive 32;
}
server {
listen 443 quic reuseport;
listen 443 ssl http2;
listen 80;
server_name example.com www.example.com;
# TLS Configuration
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1.3;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;
ssl_prefer_server_ciphers on;
# HTTP/3 specific settings
add_header Alt-Svc 'h3=":443"; ma=86400, h3-29=":443"; ma=86400, h2=":443"; ma=86400' always;
add_header Alt-Used-Protocol $server_protocol always;
# QUIC connection settings
quic_send_max_datagram_size 1200;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
Enable HTTP/3 logging:
http {
log_format quic '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'"$http3" "$http_version"';
access_log /var/log/nginx/access.log quic;
}
Caddy HTTP/3 Configuration
Caddy has native HTTP/3 support enabled by default.
Create a Caddyfile with HTTP/3:
example.com {
root * /var/www/html
file_server
encode gzip
# HTTP/3 is enabled by default
# Caddy automatically adds Alt-Svc header
# Explicitly enable HTTP/3 features
header Alt-Svc 'h3=":443"; ma=86400, h3-29=":443"; ma=86400'
}
Configure with explicit HTTP/3 options:
{
servers {
listener_wrappers {
http
tls
quic
}
}
}
example.com {
encode gzip
file_server {
root /var/www/html
}
}
For reverse proxy with HTTP/3:
api.example.com {
reverse_proxy localhost:8080 {
transport http {
protocol h3
}
}
}
UDP Port Configuration
Configure firewall rules for UDP port 443:
# UFW (Debian/Ubuntu)
sudo ufw allow 443/udp
sudo ufw allow 443/tcp
sudo ufw reload
# iptables (RHEL/CentOS)
sudo iptables -A INPUT -p udp --dport 443 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo service iptables save
# nftables
sudo nft add rule inet filter input udp dport 443 accept
sudo nft add rule inet filter input tcp dport 443 accept
Verify UDP port is open:
# From remote machine
nc -u -z -v example.com 443
# For QUIC, check with specialized tools
Configure kernel parameters for UDP performance:
# Increase UDP buffer sizes
sudo sysctl -w net.core.rmem_max=134217728
sudo sysctl -w net.core.wmem_max=134217728
sudo sysctl -w net.ipv4.udp_mem="131072 262144 524288"
# Make permanent
echo "net.core.rmem_max=134217728" | sudo tee -a /etc/sysctl.conf
echo "net.core.wmem_max=134217728" | sudo tee -a /etc/sysctl.conf
echo "net.ipv4.udp_mem=131072 262144 524288" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Alt-Svc Header Setup
The Alt-Svc header advertises HTTP/3 availability to clients:
# Nginx configuration
add_header Alt-Svc 'h3=":443"; ma=86400, h3-29=":443"; ma=86400, h2=":443"; ma=86400, http/1.1=":443"; ma=86400' always;
Header format breakdown:
Alt-Svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400, h2=":443"; ma=86400
h3: HTTP/3 on port 443h3-29: HTTP/3 draft 29 (legacy support)h2: HTTP/2 fallbackma=86400: Max age 24 hours
Include alternative ports:
add_header Alt-Svc 'h3=":443"; ma=86400, h3=":3443"; ma=86400, h2=":443"; ma=86400' always;
Caddy automatically includes Alt-Svc header when HTTP/3 is enabled.
Certificate Management
Ensure TLS 1.3 certificate support:
# Check certificate TLS version
openssl s_client -connect example.com:443 -tls1_3 < /dev/null
Generate certificate with TLS 1.3 support:
# Using Let's Encrypt (automatic)
sudo certbot certonly --standalone -d example.com
# Verify certificate
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text -noout
Caddy automatically manages Let's Encrypt certificates:
example.com {
# Certificate automatically renewed
file_server
}
Configure Nginx with certificate:
server {
listen 443 quic reuseport;
listen 443 ssl http2;
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;
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384;
}
Browser Support
HTTP/3 support varies across browsers:
Supported browsers (2024):
- Chrome/Chromium 70+
- Firefox 60+
- Safari 14.1+
- Edge 80+
- Opera 57+
- Mobile: Chrome, Firefox, Safari iOS
Check browser HTTP/3 support:
# Visit a test site
curl -I --http3 https://example.com
# Or use online tools
# https://http3check.net/
Detect HTTP/3 in browser console:
// Check if HTTP/3 is used
console.log(performance.timing);
// Look for Network tab in DevTools
Performance Testing
Test HTTP/3 performance:
# Install curl with HTTP/3 support
sudo apt install curl-http3
# Test HTTP/3 connection
curl -I --http3 https://example.com/
Benchmark HTTP/3 vs HTTP/2:
# HTTP/3 benchmark
time curl --http3 https://example.com/ > /dev/null
# HTTP/2 benchmark
time curl --http2 https://example.com/ > /dev/null
# HTTP/1.1 benchmark
time curl --http1.1 https://example.com/ > /dev/null
Load testing with HTTP/3:
# Using h3load (h3 specific load tester)
h3load -n 1000 -c 100 https://example.com/
# Using Apache Bench alternative
ab -n 1000 -c 100 https://example.com/
Monitor QUIC connections:
# Check QUIC connections on server
ss -unap | grep 443
# Monitor UDP traffic
iftop -i eth0 -f "udp port 443"
# tcpdump QUIC traffic
sudo tcpdump -i eth0 "udp port 443" -A
Troubleshooting
Verify Nginx QUIC compilation:
nginx -V | grep quic
# Output should show: --with-http_v3_module
Check HTTP/3 is advertised:
curl -I https://example.com/ | grep -i alt-svc
Test QUIC port accessibility:
# From remote machine, test UDP 443
nc -u -z -v example.com 443
# Using dig
dig +short example.com
Verify Caddy HTTP/3:
# Check Caddy logs
journalctl -u caddy -f | grep -i h3
# Test with curl
curl -I --http3 https://example.com/
Debug connection issues:
# Verbose curl with HTTP/3
curl -vvv --http3 https://example.com/
# Tcpdump QUIC handshake
sudo tcpdump -i eth0 -A "udp port 443" | head -100
Check certificate compatibility:
openssl s_client -connect example.com:443 -tls1_3 < /dev/null
Ensure firewall allows UDP:
# Test UDP connectivity
python3 -c "
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(5)
try:
s.sendto(b'test', ('example.com', 443))
except Exception as e:
print(f'UDP blocked: {e}')
"
Monitor QUIC errors:
# Nginx error log
tail -f /var/log/nginx/error.log | grep -i quic
# System messages
dmesg | grep -i quic
Conclusion
HTTP/3 and QUIC represent the future of web transport, offering significant performance improvements especially for high-latency and lossy networks. Nginx and Caddy both support HTTP/3 deployment, with Caddy providing simpler configuration out of the box. Proper firewall configuration, certificate management, and browser compatibility testing ensure smooth HTTP/3 adoption. Implement HTTP/3 with fallback to HTTP/2 to maximize performance while maintaining backward compatibility across all clients.


