Ubuntu 22.04 Nginx HTTP/3 QUIC 設定

Ubuntu 22.04 Nginx HTTP/3 QUIC Configuration

HTTP/3 是最新一代的超文字傳輸協定,基於 QUIC 協定運作,為網站帶來更快速、更可靠的連線體驗。本文將介紹如何在 Ubuntu 22.04 上設定 Nginx 以支援 HTTP/3。

HTTP/3 與 QUIC 概述

HTTP/3 是 HTTP 協定的第三個主要版本,與前代最大的不同在於它使用 QUIC(Quick UDP Internet Connections)作為傳輸層協定,而非傳統的 TCP。

QUIC 最初由 Google 開發,後來被 IETF 標準化。它具有以下特點:

  • 基於 UDP 協定運作
  • 內建 TLS 1.3 加密
  • 支援連線多工(Multiplexing)
  • 減少連線建立的延遲時間
  • 改善封包遺失時的效能表現

HTTP/3 優勢

1. 更快的連線建立

傳統的 HTTPS 連線需要經過 TCP 三次握手和 TLS 握手,共需要 2-3 個 RTT(Round-Trip Time)。HTTP/3 使用 QUIC,將這個過程縮短到 1 個 RTT,甚至在重複連線時可達到 0-RTT。

2. 解決隊頭阻塞問題

HTTP/2 雖然支援多路復用,但因為基於 TCP,當一個封包遺失時,所有串流都會被阻塞。HTTP/3 使用 QUIC,每個串流獨立處理,一個串流的封包遺失不會影響其他串流。

3. 連線遷移

QUIC 使用連線 ID 而非 IP 位址來識別連線,當使用者切換網路(如從 WiFi 切換到行動網路)時,連線可以無縫遷移,不需要重新建立。

4. 改進的壅塞控制

QUIC 實作了更先進的壅塞控制演算法,能更好地適應網路狀況的變化。

Nginx HTTP/3 支援狀態

從 Nginx 1.25.0 開始,HTTP/3 支援已進入穩定版本。在此之前,HTTP/3 功能需要使用實驗性的 nginx-quic 分支。

Ubuntu 22.04 預設的 Nginx 版本可能不支援 HTTP/3,因此我們需要從源碼編譯或使用第三方套件庫來取得支援 HTTP/3 的 Nginx 版本。

編譯支援 HTTP/3 的 Nginx

安裝編譯依賴

首先安裝必要的編譯工具和函式庫:

1
2
3
sudo apt update
sudo apt install -y build-essential git libpcre3 libpcre3-dev zlib1g zlib1g-dev \
    libssl-dev libgd-dev libgeoip-dev libxslt1-dev libperl-dev

安裝 BoringSSL 或 OpenSSL 3.x

HTTP/3 需要支援 QUIC 的 TLS 函式庫。推薦使用 BoringSSL:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 安裝 cmake 和 golang(BoringSSL 編譯需要)
sudo apt install -y cmake golang

# 下載並編譯 BoringSSL
cd /usr/local/src
sudo git clone https://github.com/google/boringssl.git
cd boringssl
sudo mkdir build && cd build
sudo cmake ..
sudo make -j$(nproc)

下載並編譯 Nginx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 下載最新版 Nginx(1.25.0 或更新版本)
cd /usr/local/src
sudo wget https://nginx.org/download/nginx-1.25.4.tar.gz
sudo tar -xzf nginx-1.25.4.tar.gz
cd nginx-1.25.4

# 設定編譯選項
sudo ./configure \
    --prefix=/etc/nginx \
    --sbin-path=/usr/sbin/nginx \
    --modules-path=/usr/lib64/nginx/modules \
    --conf-path=/etc/nginx/nginx.conf \
    --error-log-path=/var/log/nginx/error.log \
    --http-log-path=/var/log/nginx/access.log \
    --pid-path=/var/run/nginx.pid \
    --lock-path=/var/run/nginx.lock \
    --with-http_ssl_module \
    --with-http_v2_module \
    --with-http_v3_module \
    --with-cc-opt="-I/usr/local/src/boringssl/include" \
    --with-ld-opt="-L/usr/local/src/boringssl/build/ssl -L/usr/local/src/boringssl/build/crypto"

# 編譯並安裝
sudo make -j$(nproc)
sudo make install

驗證安裝

1
nginx -V

確認輸出中包含 --with-http_v3_module

設定 HTTP/3

編輯 Nginx 設定檔以啟用 HTTP/3:

1
sudo nano /etc/nginx/nginx.conf

基本 HTTP/3 設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
http {
    # 啟用 QUIC 和 HTTP/3 日誌
    log_format quic '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    '$http3';

    server {
        # HTTP/1.1 和 HTTP/2(TCP)
        listen 443 ssl;
        listen [::]:443 ssl;

        # HTTP/3(QUIC over UDP)
        listen 443 quic reuseport;
        listen [::]:443 quic reuseport;

        server_name example.com www.example.com;

        # SSL 憑證設定
        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        # TLS 設定
        ssl_protocols TLSv1.3;
        ssl_prefer_server_ciphers off;

        # QUIC 設定
        ssl_early_data on;
        quic_retry on;

        # 回應標頭:告知瀏覽器支援 HTTP/3
        add_header Alt-Svc 'h3=":443"; ma=86400';

        # 使用 QUIC 日誌格式
        access_log /var/log/nginx/access.log quic;

        root /var/www/html;
        index index.html;

        location / {
            try_files $uri $uri/ =404;
        }
    }
}

完整的生產環境設定範例

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # 日誌格式
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    log_format quic '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    'quic=$http3 early_data=$ssl_early_data';

    # 效能優化
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    # Gzip 壓縮
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript
               application/rss+xml application/atom+xml image/svg+xml;

    # HTTP 重導向至 HTTPS
    server {
        listen 80;
        listen [::]:80;
        server_name example.com www.example.com;
        return 301 https://$server_name$request_uri;
    }

    # HTTPS + HTTP/3 設定
    server {
        listen 443 ssl;
        listen [::]:443 ssl;
        listen 443 quic reuseport;
        listen [::]:443 quic reuseport;

        server_name example.com www.example.com;

        # SSL 憑證
        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;

        # TLS 設定
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
        ssl_prefer_server_ciphers off;
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_session_tickets off;

        # OCSP Stapling
        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 8.8.8.8 8.8.4.4 valid=300s;
        resolver_timeout 5s;

        # HTTP/3 和 QUIC 設定
        ssl_early_data on;
        quic_retry on;
        quic_gso on;

        # Alt-Svc 標頭
        add_header Alt-Svc 'h3=":443"; ma=86400' always;

        # 安全標頭
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

        access_log /var/log/nginx/access.log quic;
        error_log /var/log/nginx/error.log;

        root /var/www/html;
        index index.html index.htm;

        location / {
            try_files $uri $uri/ =404;
        }
    }
}

Alt-Svc 標頭

Alt-Svc(Alternative Services)標頭是告知瀏覽器伺服器支援 HTTP/3 的關鍵機制。

1
add_header Alt-Svc 'h3=":443"; ma=86400' always;

參數說明:

  • h3=":443":表示在連接埠 443 上提供 HTTP/3 服務
  • ma=86400:max-age,快取時間為 86400 秒(24 小時)
  • always:確保此標頭在所有回應中都會發送

瀏覽器首次訪問時會使用 HTTP/1.1 或 HTTP/2,收到 Alt-Svc 標頭後,後續請求會嘗試使用 HTTP/3。

防火牆設定(UDP 443)

HTTP/3 使用 UDP 協定在 443 連接埠運作,因此需要開放 UDP 443:

使用 UFW

1
2
3
4
5
6
7
8
# 允許 TCP 443(HTTP/1.1 和 HTTP/2)
sudo ufw allow 443/tcp

# 允許 UDP 443(HTTP/3)
sudo ufw allow 443/udp

# 查看防火牆規則
sudo ufw status

使用 iptables

1
2
3
4
5
6
7
8
# 允許 TCP 443
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 允許 UDP 443
sudo iptables -A INPUT -p udp --dport 443 -j ACCEPT

# 儲存規則
sudo iptables-save | sudo tee /etc/iptables/rules.v4

雲端平台安全群組

如果您的伺服器位於 AWS、GCP 或 Azure 等雲端平台,請確保在安全群組或防火牆規則中同時允許 TCP 443 和 UDP 443 的輸入流量。

測試 HTTP/3 連線

驗證設定並重啟 Nginx

1
2
3
4
5
6
7
8
# 測試設定檔語法
sudo nginx -t

# 重新啟動 Nginx
sudo systemctl restart nginx

# 查看服務狀態
sudo systemctl status nginx

使用 curl 測試

如果您的 curl 版本支援 HTTP/3(需要 curl 7.66.0 以上並使用 HTTP/3 支援編譯):

1
2
3
4
5
# 測試 HTTP/3 連線
curl --http3 -I https://example.com

# 強制使用 HTTP/3
curl --http3-only -I https://example.com

使用線上工具測試

瀏覽器開發者工具

在 Chrome 或 Firefox 的開發者工具中,網路分頁的 Protocol 欄位會顯示 h3 表示正在使用 HTTP/3。

效能考量

1. 適用場景

HTTP/3 在以下場景效益最明顯:

  • 高延遲網路環境
  • 網路狀況不穩定的行動裝置使用者
  • 需要頻繁建立新連線的應用
  • 大量小檔案的傳輸

2. 資源消耗

QUIC 的加密和解密在用戶端進行,可能增加 CPU 使用率。確保伺服器有足夠的運算資源。

3. 監控指標

建議監控以下指標:

  • QUIC 連線數
  • 0-RTT 使用率
  • 連線遷移次數
  • UDP 封包遺失率

4. 回退機制

確保 HTTP/1.1 和 HTTP/2 仍然可用,以便在 HTTP/3 連線失敗時能夠回退:

1
2
listen 443 ssl;          # HTTP/1.1 和 HTTP/2
listen 443 quic;         # HTTP/3

疑難排解

常見問題

  1. 無法建立 QUIC 連線

    • 檢查防火牆是否允許 UDP 443
    • 確認 SSL 憑證有效且正確設定
  2. Alt-Svc 標頭未發送

    • 確認 add_header 指令包含 always 參數
    • 檢查是否有其他 location 區塊覆蓋了標頭設定
  3. 效能未改善

    • HTTP/3 在低延遲網路中的優勢較不明顯
    • 檢查是否正確啟用了 0-RTT

查看 QUIC 連線日誌

1
2
# 查看 QUIC 相關日誌
sudo tail -f /var/log/nginx/access.log | grep -E 'h3|quic'

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy