跳到內容

提供 HTTP/3

HTTP/3 預設開啟:除非全域協定清單排除了 h3,否則 HTTPS 網站都會在 UDP 443 啟用 QUIC 監聽器。請檢查回應使用的協定版本;用戶端可能在 HTTP/3 連線失敗後改用 HTTP/2。

📌 本頁描述 v0.2.2。

  • 一個解析到這台主機的名稱,以及它的憑證(HTTPS)。

  • 在供應商與主機的防火牆上都 開放 UDP 443。UDP 被擋住時,用戶端可能改用 HTTP/2。

  • 支援 HTTP/3 的用戶端。多數發行版內建的 curl 不支援 HTTP/3,執行時會顯示下列錯誤:

    curl: option --http3: the installed libcurl version doesn't support this
{
email bonjour@pingclair.com
servers {
protocols h1 h2 h3
}
}
example.com {
file_server /srv/site
}

網站啟動後,在主機上檢查 UDP 監聽器:

終端機視窗
sudo ss -lunp | grep ':443 '
UNCONN 0 0 *:443 *:* users:(("pingclair",pid=5425,fd=22))

從清單中移除 h3,這個監聽器就會消失;這份清單就是開關(TLS:可以調整什麼)。沒有 protocols 這一行時,HTTP/3 維持開啟。

tls 區塊也接受個別網站的開關:

example.com {
tls {
http3 off
}
file_server /srv/site
}

http3 off 會拒絕該網站的 QUIC 握手,並停止在 Alt-Svc 宣告 HTTP/3。同一連接埠的其他網站仍可使用 QUIC。

證據要從用戶端取得。任何以 ngtcp2 或 quiche 建置的 curl 都可以;在 curl 不支援 HTTP/3 的主機上,用容器是取得它最快的方式:

終端機視窗
docker run --rm --network host \
ymuski/curl-http3 curl -sI --http3 https://example.com/
curl 8.2.1-DEV (x86_64-pc-linux-gnu) libcurl/8.2.1-DEV BoringSSL zlib/1.2.13 nghttp2/1.52.0 quiche/0.18.0

--network host 讓容器直接使用主機的網路。少了它,請求可能會經過一個擋掉 QUIC 的網路命名空間。

HTTP/3 200
content-type: text/html; charset=utf-8
etag: "5e-6ab20622"
accept-ranges: bytes
x-served-by: pingclair
server: Pingclair

答案就在第一行:狀態列寫的是 HTTP/3,而不是 HTTP/2。對同一個 URL 分別用 --http2 與 --http1.1 請求,會顯示另外兩種協定,這就確認了用戶端沒有退回。

沒有容器可用時,若系統的 OpenSSL 是 3.5 或更新版本,可以用它檢查 QUIC 交握:

終端機視窗
openssl s_client -quic -alpn h3 -connect example.com:443 -servername example.com </dev/null
Protocol: QUICv1
ALPN protocol: h3
Protocol : TLSv1.3
Verify return code: 0 (ok)

ALPN protocol: h3 加上通過驗證的憑證鏈,證明 QUIC 監聽器會以用戶端信任的憑證回應這個名稱。但它無法證明完整的 HTTP/3 請求可以運作;那要靠 curl 的檢查。

HTTP/3 與 HTTP/1.1、HTTP/2 共用政策程式碼,所以路由、匹配器、標頭、速率限制、FastCGI 與存取日誌的行為都相同。差異出現在 HTTP/3 無法承載某些東西的地方:

領域 在 HTTP/3 上
宣告的 request trailers 與每種協定一樣不轉送:回應確定送出前回 501;在 HTTP/3 上,之後則重設 stream。
上游回應的 trailers 與每種協定一樣轉送:來源的狀態與本文會到用戶端,trailer 欄位則被丟棄。
CONNECT Pingclair 不建立 tunnel。可用的 host:port 目標得到附帶 Allow 的 405;沒有可用連接埠的目標得到 400。HTTP/1.1 拒絕後關閉連線。

trailer 欄位是表中唯一的刻意分歧:Caddy 與 nginx 會把來源的 trailer 欄位 轉送給用戶端,這裡則轉送 Trailer: 宣告、丟棄其後的欄位——讀到宣告的 用戶端會等待永遠不會到的欄位(#273)。

源站前面若有 CDN,CDN 會自己終結 HTTP/3,再以 HTTP/1.1 或 HTTP/2 與源站溝通。這時這裡的監聽器完全無法告訴你訪客的瀏覽器用了什麼;請改查 CDN 本身的 HTTP/3 設定。

  • option --http3: the installed libcurl version doesn't support this。 用戶端不支援 HTTP/3;請照上面的方式使用容器。
  • curl --http3 卡住或逾時。 UDP 443 可能被封鎖。請先檢查供應商的防火牆或安全群組,再檢查主機本身的。
  • 主機上沒有 UDP 監聽器。 servers 的協定清單中少了 h3,或正在執行的檔案不是你編輯的那一份(重載意味著什麼)。
  • HTTP/3 在本機可以用,從外部卻不行。 用戶端所在的網路可能封鎖 UDP 443;瀏覽器可能改用 HTTP/2。