Setting Up HTTP/3 with Caddy Server
Prerequisites
HTTP/3 operates over QUIC (UDP-based) instead of TCP, making the setup more demanding than HTTP/2.
HTPS Certificate
HTTP/3 requires a valid security certificate. Unlike HTTP/2, insecure certificates will not work at all.
Install mkcert for local development:
winget install mkcert
Initialize the local certificate authority:
mkcert -install
Generate a certificate for localhost:
mkcert localhost 127.0.0.1 ::1
Configure Caddyfile:
tls ./localhost+2.pem ./localhost+2-key.pem
Alt-Svc Header
The server must announce the UDP port via the Alt-Svc response header:
header Alt-Svc `h3=":8443"; ma=2592000, h3-29=":8443"; ma=2592000`
UDP Port Accesibility
Caddy may open only IPv6 UDP ports by default. Verify open UDP endpoints using PowerShell:
Get-NetUDPEndpoint | Select-Object LocalAddress, LocalPort, OwningProcess
Filter by specific port:
PS D:\www> Get-NetUDPEndpoint -LocalPort 8443 | Select-Object LocalAddress, LocalPort, OwningProcess
LocalAddress LocalPort OwningProcess
------------ --------- -------------
:: 8443 81976
Browser Configuration
Chrome requires explicit flags to enable HTTP/3. Launch Chrome with QUIC forcing enabled:
& "C:\Users\32956\AppData\Local\Google\Chrome\Application\chrome.exe" `
--user-data-dir="$env:TEMP\chrome_h3_test" `
--origin-to-force-quic-on=127.0.0.1:8443 `
--force-quic `
--ignore-certificate-errors `
"https://127.0.0.1:8443/image-hosts"
If HTTP/3 fails, the browser will not fallback to HTTP/2.
Testing HTTP/3 Connectivity
Use the aioquic library to verify QUIC handshake:
# /// script
# dependencies = ["aioquic"]
# ///
import asyncio
from aioquic.quic.configuration import QuicConfiguration
from aioquic.asyncio import connect
async def test_quic_connection():
config = QuicConfiguration(is_client=True, alpn_protocols=["h3"])
config.verify_mode = 0
try:
async with connect("127.0.0.1", 8443, configuration=config) as client:
print("QUIC handshake successful - HTTP/3 is working")
except Exception as err:
print(f"Connection failed: {err}")
if __name__ == "__main__":
asyncio.run(test_quic_connection())
Protocol Compatibility
| Protocol | Transport | Requirements |
|---|---|---|
| HTTP/1.1 | TCP | Minimal |
| HTTP/2 | TCP | HTTPS recommended |
| HTTP/3 | UDP | Valid certificate + Alt-Svc header |
HTTP/3 has the strictest requirements among all HTTP verisons.
Network Considerations
When using reverse proxy services or tunnel forwarding, separate tunnels are needed for TCP and UDP traffic. This adds complexity to the configuration compared to traditional HTTP setups.