HTTP/3 uses QUIC (UDP-based transport) instead of TCP, offering faster connections, better performance on lossy networks, and built-in encryption. Nginx added HTTP/3 support in version 1.25+. This guide covers enabling HTTP/3 on your VPS for faster web delivery.
Prerequisites
# Check Nginx version (need 1.25.0+)
nginx -v
# Check if built with HTTP/3 support
nginx -V 2>&1 | grep -o "http_v3_module"
# If not, install or build Nginx with QUIC/HTTP3
# Ubuntu 24.04+ includes HTTP/3 support in the mainline package
sudo apt install nginx # or nginx-mainline
# Or build from source with HTTP/3
wget https://nginx.org/download/nginx-1.27.0.tar.gz
tar xzf nginx-1.27.0.tar.gz
cd nginx-1.27.0
./configure --with-http_v3_module --with-stream_quic_module --with-cc-opt="-I/usr/include/openssl"
make && sudo make install
Configure HTTP/3
server {
# HTTP/2 over TCP (standard HTTPS)
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
# HTTP/3 over QUIC (UDP)
listen 443 quic reuseport;
listen [::]:443 quic reuseport;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# TLS 1.3 required for HTTP/3
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
# QUIC settings
ssl_early_data on; # 0-RTT
quic_retry on; # Address validation
quic_gso on; # Generic Segmentation Offload
# Tell browsers that HTTP/3 is available
add_header Alt-Svc 'h3=":443"; ma=86400' always;
# QUIC transport parameters
# quic_active_connection_id_limit 2;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Firewall Configuration
# QUIC uses UDP port 443 — must be open!
sudo ufw allow 443/tcp # HTTPS (HTTP/2)
sudo ufw allow 443/udp # QUIC (HTTP/3)
# iptables
sudo iptables -A INPUT -p udp --dport 443 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
Verify HTTP/3
# Using curl (requires HTTP/3 support)
curl --http3 -I https://example.com
# Look for: HTTP/3 200
# Or check Alt-Svc header (HTTP/2 response tells browser to try HTTP/3)
curl -sI https://example.com | grep alt-svc
# Should show: alt-svc: h3=":443"; ma=86400
# Online tools:
# https://http3check.net
# https://www.http3.dev
# Chrome DevTools: Network tab > Protocol column shows "h3"
0-RTT (Early Data)
# 0-RTT allows sending data with the first packet (no round-trip wait)
# Already enabled with: ssl_early_data on;
# WARNING: 0-RTT is vulnerable to replay attacks
# Protect sensitive endpoints:
location /api/payment {
# Reject 0-RTT for state-changing operations
if ($ssl_early_data) {
return 425; # Too Early
}
proxy_pass http://backend;
}
Performance Benefits
- Faster initial connection: 1-RTT (or 0-RTT for repeat visits) vs TCP's 3-way handshake + TLS
- No head-of-line blocking: Lost packets on one stream don't block other streams
- Connection migration: Connections survive network changes (Wi-Fi to cellular)
- Better on lossy networks: Significantly faster on mobile and high-latency connections
Best Practices
- Always keep HTTP/2 as fallback: Not all clients support HTTP/3 yet
- Open UDP 443: The most common mistake — QUIC uses UDP, not TCP
- Use
reuseporton the QUIC listener for better multi-core performance - Enable
quic_retryfor address validation and DDoS protection - Set the Alt-Svc header so browsers discover HTTP/3 availability
- Protect against 0-RTT replay on state-changing API endpoints