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

  1. HTTP/3 and QUIC Overview
  2. System Requirements
  3. Nginx QUIC Configuration
  4. Caddy HTTP/3 Configuration
  5. UDP Port Configuration
  6. Alt-Svc Header Setup
  7. Certificate Management
  8. Browser Support
  9. Performance Testing
  10. 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 443
  • h3-29: HTTP/3 draft 29 (legacy support)
  • h2: HTTP/2 fallback
  • ma=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.