Ubuntu 22.04 Nginx Brotli 壓縮設定

Ubuntu 22.04 Nginx Brotli Compression Configuration

前言

在現代網頁效能優化中,壓縮技術扮演著至關重要的角色。Brotli 是由 Google 開發的新一代壓縮演算法,相較於傳統的 Gzip,能夠提供更高的壓縮率與更快的解壓縮速度。本文將詳細介紹如何在 Ubuntu 22.04 系統上為 Nginx 設定 Brotli 壓縮功能。

Brotli 壓縮演算法介紹

什麼是 Brotli?

Brotli 是 Google 於 2015 年發布的開源無損壓縮演算法,最初設計用於網頁字型壓縮(WOFF2 格式)。其名稱源自瑞士德語中的一種麵包「Brötli」。Brotli 採用了多種先進的壓縮技術:

  • LZ77 演算法:用於尋找並消除重複的資料序列
  • Huffman 編碼:進行熵編碼以減少位元數
  • 二階上下文建模:根據上下文預測下一個符號
  • 預定義字典:包含超過 120,000 個常見網頁內容的字串

Brotli 的優勢

  1. 更高的壓縮率:相同品質下,Brotli 比 Gzip 能多壓縮 15-25% 的檔案大小
  2. 更快的解壓縮速度:瀏覽器端解壓縮效能優異
  3. 專為網頁優化:內建的字典包含常見的 HTML、CSS、JavaScript 程式碼片段
  4. 靈活的壓縮等級:支援 0-11 級壓縮,可根據需求調整

Brotli 與 Gzip 的比較

特性BrotliGzip
壓縮率較高(約多 15-25%)標準
壓縮速度較慢(高壓縮等級時)較快
解壓縮速度快速快速
瀏覽器支援現代瀏覽器(需 HTTPS)所有瀏覽器
CPU 使用率較高(壓縮時)較低
壓縮等級0-111-9

實際測試數據

以下是常見檔案類型的壓縮比較(原始檔案大小 100KB):

1
2
3
4
5
檔案類型        Gzip (等級 9)    Brotli (等級 11)    節省空間
HTML            25.2 KB          21.3 KB             15.5%
CSS             18.7 KB          15.1 KB             19.3%
JavaScript      22.4 KB          18.6 KB             17.0%
JSON            19.8 KB          16.2 KB             18.2%

Nginx Brotli 模組安裝

方法一:使用 nginx-extras 套件(推薦)

Ubuntu 22.04 提供了包含 Brotli 模組的 nginx-extras 套件:

1
2
3
4
5
6
7
8
# 更新套件清單
sudo apt update

# 安裝 nginx-extras(包含 Brotli 模組)
sudo apt install nginx-extras -y

# 驗證安裝
nginx -V 2>&1 | grep -o 'brotli'

方法二:使用第三方 PPA

如果需要更新版本的 Nginx 與 Brotli 模組:

1
2
3
4
5
6
7
8
9
# 新增 ondrej/nginx PPA
sudo add-apt-repository ppa:ondrej/nginx -y

# 更新並安裝
sudo apt update
sudo apt install nginx libnginx-mod-brotli -y

# 確認模組已載入
nginx -V 2>&1 | grep -i brotli

方法三:從原始碼編譯

若需要完全控制編譯選項,可從原始碼編譯:

 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
# 安裝編譯所需的相依套件
sudo apt install -y build-essential git libpcre3 libpcre3-dev \
    zlib1g zlib1g-dev libssl-dev libgd-dev libgeoip-dev

# 下載 Brotli 模組原始碼
cd /usr/local/src
sudo git clone https://github.com/google/ngx_brotli.git
cd ngx_brotli
sudo git submodule update --init

# 下載 Nginx 原始碼(請使用與系統相同的版本)
NGINX_VERSION=$(nginx -v 2>&1 | grep -oP 'nginx/\K[\d.]+')
cd /usr/local/src
sudo wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz
sudo tar -xzvf nginx-${NGINX_VERSION}.tar.gz
cd nginx-${NGINX_VERSION}

# 取得現有 Nginx 的編譯參數
nginx -V 2>&1 | grep 'configure arguments'

# 編譯動態模組
sudo ./configure --with-compat --add-dynamic-module=/usr/local/src/ngx_brotli
sudo make modules

# 複製模組到 Nginx 模組目錄
sudo cp objs/ngx_http_brotli_filter_module.so /usr/share/nginx/modules/
sudo cp objs/ngx_http_brotli_static_module.so /usr/share/nginx/modules/

載入動態模組

如果使用動態模組,需要在 Nginx 設定檔中載入:

1
2
# 編輯 /etc/nginx/nginx.conf
sudo nano /etc/nginx/nginx.conf

在檔案開頭(http 區塊之前)加入:

1
2
load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;

壓縮設定與參數調校

基本設定

/etc/nginx/nginx.confhttp 區塊中加入 Brotli 設定:

 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
http {
    # Brotli 壓縮設定
    brotli on;
    brotli_comp_level 6;
    brotli_static on;
    brotli_types
        text/plain
        text/css
        text/javascript
        text/xml
        text/x-component
        application/javascript
        application/x-javascript
        application/json
        application/xml
        application/rss+xml
        application/atom+xml
        application/vnd.ms-fontobject
        application/x-font-ttf
        application/x-font-opentype
        application/x-font-truetype
        font/eot
        font/opentype
        font/otf
        font/ttf
        image/svg+xml
        image/x-icon
        image/vnd.microsoft.icon;

    # 設定最小壓縮檔案大小
    brotli_min_length 256;

    # 同時啟用 Gzip 作為備援
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/javascript
        text/xml
        application/javascript
        application/json
        application/xml
        application/rss+xml
        font/ttf
        font/otf
        image/svg+xml;
}

參數詳解

參數說明建議值
brotli啟用或停用 Brotli 壓縮on
brotli_comp_level壓縮等級(0-11)4-6(平衡效能與壓縮率)
brotli_static啟用預壓縮靜態檔案on
brotli_types要壓縮的 MIME 類型文字類型與字型
brotli_min_length最小壓縮檔案大小256 位元組
brotli_buffers壓縮緩衝區設定16 8k
brotli_window滑動視窗大小512k

進階設定範例

 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
http {
    # Brotli 進階設定
    brotli on;
    brotli_comp_level 6;
    brotli_static on;
    brotli_min_length 256;
    brotli_buffers 16 8k;
    brotli_window 512k;

    brotli_types
        application/atom+xml
        application/geo+json
        application/javascript
        application/x-javascript
        application/json
        application/ld+json
        application/manifest+json
        application/rdf+xml
        application/rss+xml
        application/vnd.ms-fontobject
        application/wasm
        application/x-web-app-manifest+json
        application/xhtml+xml
        application/xml
        font/eot
        font/otf
        font/ttf
        image/bmp
        image/svg+xml
        text/cache-manifest
        text/calendar
        text/css
        text/javascript
        text/markdown
        text/plain
        text/xml
        text/vcard
        text/vnd.rim.location.xloc
        text/vtt
        text/x-component
        text/x-cross-domain-policy;

    # 根據位置設定不同壓縮等級
    map $uri $brotli_level {
        default         6;
        ~*\.json$       4;
        ~*\.js$         5;
        ~*\.css$        5;
        ~*\.html$       6;
        ~*\.svg$        11;
    }
}

靜態檔案預壓縮

為什麼要預壓縮?

即時壓縮會消耗 CPU 資源,對於不常變動的靜態檔案,預先壓縮可以:

  1. 減少伺服器 CPU 負載
  2. 使用更高的壓縮等級
  3. 加快回應速度

安裝 Brotli 命令列工具

1
sudo apt install brotli -y

手動預壓縮

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 壓縮單一檔案
brotli -k -q 11 /var/www/html/styles.css
# -k: 保留原始檔案
# -q: 壓縮品質(0-11)

# 批次壓縮目錄中的檔案
find /var/www/html -type f \( -name "*.html" -o -name "*.css" -o -name "*.js" -o -name "*.svg" -o -name "*.json" \) -exec brotli -k -q 11 {} \;

# 查看壓縮結果
ls -la /var/www/html/*.br

自動化預壓縮腳本

建立 /usr/local/bin/brotli-compress.sh

 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
#!/bin/bash
# Brotli 預壓縮腳本

WEB_ROOT="/var/www/html"
QUALITY=11
EXTENSIONS="html css js svg json xml txt"

echo "開始 Brotli 預壓縮..."
echo "目標目錄: $WEB_ROOT"
echo "壓縮品質: $QUALITY"

for ext in $EXTENSIONS; do
    echo "處理 .$ext 檔案..."
    find "$WEB_ROOT" -type f -name "*.$ext" | while read file; do
        # 檢查 .br 檔案是否存在且比原始檔案新
        if [ ! -f "${file}.br" ] || [ "$file" -nt "${file}.br" ]; then
            brotli -k -q $QUALITY -f "$file"
            echo "已壓縮: $file"
        fi
    done
done

echo "預壓縮完成!"

# 顯示壓縮統計
echo ""
echo "=== 壓縮統計 ==="
for ext in $EXTENSIONS; do
    original=$(find "$WEB_ROOT" -type f -name "*.$ext" -exec stat -c%s {} + 2>/dev/null | awk '{sum+=$1} END {print sum}')
    compressed=$(find "$WEB_ROOT" -type f -name "*.$ext.br" -exec stat -c%s {} + 2>/dev/null | awk '{sum+=$1} END {print sum}')
    if [ -n "$original" ] && [ "$original" -gt 0 ]; then
        ratio=$(echo "scale=2; (1 - $compressed / $original) * 100" | bc)
        echo "$ext: 原始 $(numfmt --to=iec $original), 壓縮後 $(numfmt --to=iec $compressed), 節省 ${ratio}%"
    fi
done

設定執行權限並加入排程:

1
2
3
4
5
# 設定執行權限
sudo chmod +x /usr/local/bin/brotli-compress.sh

# 加入 crontab(每天凌晨 3 點執行)
echo "0 3 * * * /usr/local/bin/brotli-compress.sh >> /var/log/brotli-compress.log 2>&1" | sudo crontab -

Nginx 靜態 Brotli 設定

確保 brotli_static 已啟用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
server {
    listen 443 ssl http2;
    server_name example.com;
    root /var/www/html;

    # 啟用預壓縮檔案
    brotli_static on;
    gzip_static on;

    location ~* \.(css|js|html|svg|json)$ {
        # Nginx 會自動尋找 .br 檔案
        brotli_static on;
        gzip_static on;

        # 快取設定
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

瀏覽器相容性

支援 Brotli 的瀏覽器

瀏覽器最低版本備註
Chrome50+2016 年起支援
Firefox44+2016 年起支援
Safari11+2017 年起支援
Edge15+2017 年起支援
Opera36+2016 年起支援
iOS Safari11+2017 年起支援
Android Chrome50+2016 年起支援

重要限制

  1. 僅支援 HTTPS:基於安全考量,瀏覽器只在 HTTPS 連線時才會接受 Brotli 壓縮
  2. Accept-Encoding 標頭:瀏覽器必須在請求中包含 br 編碼

檢查瀏覽器支援

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 前端檢測 Brotli 支援
function checkBrotliSupport() {
    // 檢查是否為 HTTPS
    if (location.protocol !== 'https:') {
        console.log('Brotli 需要 HTTPS 連線');
        return false;
    }

    // 現代瀏覽器通常都支援
    // 可透過發送測試請求確認
    fetch('/test.js', { method: 'HEAD' })
        .then(response => {
            const encoding = response.headers.get('Content-Encoding');
            console.log('Content-Encoding:', encoding);
            return encoding === 'br';
        });
}

Nginx 回退設定

確保不支援 Brotli 的瀏覽器能正常使用 Gzip:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
http {
    # Brotli(優先)
    brotli on;
    brotli_comp_level 6;
    brotli_types text/plain text/css application/javascript application/json;

    # Gzip(回退)
    gzip on;
    gzip_vary on;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/javascript application/json;

    # 根據 Accept-Encoding 自動選擇
    # Nginx 會自動處理,優先使用 Brotli
}

效能測試與基準

使用 curl 測試壓縮

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 測試 Brotli 壓縮
curl -H "Accept-Encoding: br" -I https://example.com/styles.css

# 測試 Gzip 壓縮
curl -H "Accept-Encoding: gzip" -I https://example.com/styles.css

# 比較回應大小
curl -H "Accept-Encoding: br" -so /dev/null -w '%{size_download}' https://example.com/styles.css
curl -H "Accept-Encoding: gzip" -so /dev/null -w '%{size_download}' https://example.com/styles.css
curl -so /dev/null -w '%{size_download}' https://example.com/styles.css

壓縮效能測試腳本

建立 /usr/local/bin/compression-benchmark.sh

 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
#!/bin/bash
# 壓縮效能基準測試

URL="https://example.com"
TEST_FILES=(
    "/styles.css"
    "/app.js"
    "/index.html"
    "/data.json"
)

echo "壓縮效能基準測試"
echo "=================="
echo ""

printf "%-30s %10s %10s %10s %10s %10s\n" "檔案" "原始" "Gzip" "Brotli" "Gzip%" "Brotli%"
printf "%s\n" "--------------------------------------------------------------------------------"

for file in "${TEST_FILES[@]}"; do
    # 原始大小
    original=$(curl -so /dev/null -w '%{size_download}' "${URL}${file}" 2>/dev/null)

    # Gzip 大小
    gzip_size=$(curl -H "Accept-Encoding: gzip" -so /dev/null -w '%{size_download}' "${URL}${file}" 2>/dev/null)

    # Brotli 大小
    brotli_size=$(curl -H "Accept-Encoding: br" -so /dev/null -w '%{size_download}' "${URL}${file}" 2>/dev/null)

    # 計算節省百分比
    if [ "$original" -gt 0 ]; then
        gzip_saving=$(echo "scale=1; (1 - $gzip_size / $original) * 100" | bc)
        brotli_saving=$(echo "scale=1; (1 - $brotli_size / $original) * 100" | bc)
    else
        gzip_saving="N/A"
        brotli_saving="N/A"
    fi

    printf "%-30s %10s %10s %10s %9s%% %9s%%\n" \
        "$file" "$original" "$gzip_size" "$brotli_size" "$gzip_saving" "$brotli_saving"
done

echo ""
echo "回應時間測試"
echo "============"

for file in "${TEST_FILES[@]}"; do
    echo ""
    echo "檔案: $file"

    # 無壓縮
    time_none=$(curl -so /dev/null -w '%{time_total}' "${URL}${file}" 2>/dev/null)

    # Gzip
    time_gzip=$(curl -H "Accept-Encoding: gzip" -so /dev/null -w '%{time_total}' "${URL}${file}" 2>/dev/null)

    # Brotli
    time_brotli=$(curl -H "Accept-Encoding: br" -so /dev/null -w '%{time_total}' "${URL}${file}" 2>/dev/null)

    echo "  無壓縮: ${time_none}s"
    echo "  Gzip:   ${time_gzip}s"
    echo "  Brotli: ${time_brotli}s"
done

使用 Apache Bench 進行負載測試

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 安裝 Apache Bench
sudo apt install apache2-utils -y

# 測試 Brotli 壓縮效能
ab -n 1000 -c 10 -H "Accept-Encoding: br" https://example.com/styles.css

# 測試 Gzip 壓縮效能
ab -n 1000 -c 10 -H "Accept-Encoding: gzip" https://example.com/styles.css

# 測試無壓縮效能
ab -n 1000 -c 10 https://example.com/styles.css

監控 CPU 使用率

1
2
3
4
5
6
7
8
# 安裝 sysstat
sudo apt install sysstat -y

# 監控 Nginx 程序 CPU 使用率
pidstat -p $(pgrep -d',' nginx) 1

# 或使用 htop 篩選 nginx 程序
htop -p $(pgrep -d',' nginx)

最佳實務

壓縮等級選擇指南

使用情境建議等級說明
即時壓縮4-6平衡 CPU 使用與壓縮率
預壓縮靜態檔案11最高壓縮率,一次壓縮多次傳輸
高流量網站1-4減少 CPU 負載
API 回應4-5快速壓縮動態內容

完整的生產環境設定

 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
# /etc/nginx/conf.d/compression.conf

# Brotli 設定
brotli on;
brotli_comp_level 6;
brotli_static on;
brotli_min_length 256;
brotli_buffers 16 8k;
brotli_window 512k;
brotli_types
    application/atom+xml
    application/javascript
    application/json
    application/ld+json
    application/manifest+json
    application/rss+xml
    application/vnd.geo+json
    application/vnd.ms-fontobject
    application/wasm
    application/x-font-ttf
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    font/otf
    font/ttf
    image/bmp
    image/svg+xml
    image/x-icon
    text/cache-manifest
    text/calendar
    text/css
    text/javascript
    text/markdown
    text/plain
    text/xml
    text/vcard
    text/vtt
    text/x-component
    text/x-cross-domain-policy;

# Gzip 設定(回退)
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 256;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/ld+json
    application/manifest+json
    application/rss+xml
    application/vnd.geo+json
    application/vnd.ms-fontobject
    application/x-font-ttf
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    font/otf
    font/ttf
    image/bmp
    image/svg+xml
    image/x-icon
    text/cache-manifest
    text/css
    text/javascript
    text/plain
    text/xml
    text/vcard
    text/vtt
    text/x-component;

故障排除

問題一:Brotli 未生效

檢查步驟:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 1. 確認模組已載入
nginx -V 2>&1 | grep brotli

# 2. 檢查設定檔語法
sudo nginx -t

# 3. 確認使用 HTTPS
curl -I https://example.com/styles.css | grep -i content-encoding

# 4. 檢查 Accept-Encoding 標頭
curl -H "Accept-Encoding: br, gzip, deflate" -I https://example.com/styles.css

常見原因:

  • 未使用 HTTPS
  • 模組未正確載入
  • MIME 類型未包含在 brotli_types
  • 檔案大小小於 brotli_min_length

問題二:CPU 使用率過高

解決方案:

1
2
3
4
5
6
7
8
# 降低壓縮等級
brotli_comp_level 4;

# 增加最小壓縮大小
brotli_min_length 1024;

# 使用預壓縮
brotli_static on;

問題三:預壓縮檔案未使用

檢查步驟:

1
2
3
4
5
6
7
8
# 確認 .br 檔案存在
ls -la /var/www/html/*.br

# 確認檔案權限
stat /var/www/html/styles.css.br

# 確認 Nginx 使用者可讀取
sudo -u www-data cat /var/www/html/styles.css.br > /dev/null && echo "OK"

問題四:與 CDN 的相容性

某些 CDN 可能會移除或修改壓縮設定。確保:

  1. CDN 支援 Brotli 壓縮
  2. 正確設定 Vary: Accept-Encoding 標頭
  3. CDN 快取考慮 Accept-Encoding 標頭
1
2
# 確保 Vary 標頭正確設定
add_header Vary "Accept-Encoding";

效能優化檢查清單

  • 啟用 Brotli 動態壓縮
  • 設定適當的壓縮等級(建議 4-6)
  • 啟用 Brotli 靜態壓縮
  • 預壓縮靜態資源(等級 11)
  • 設定 Gzip 作為回退方案
  • 確認所有需要的 MIME 類型都已包含
  • 設定適當的 brotli_min_length
  • 驗證 HTTPS 已正確設定
  • 測試瀏覽器相容性
  • 監控 CPU 使用率
  • 設定自動化預壓縮排程

結論

Brotli 壓縮是提升網站效能的有效手段,在 Ubuntu 22.04 上配合 Nginx 使用可以顯著減少傳輸大小,提升使用者體驗。透過本文的設定指南,您可以:

  1. 正確安裝並設定 Nginx Brotli 模組
  2. 根據網站特性調整壓縮參數
  3. 實施預壓縮策略以減少 CPU 負載
  4. 確保舊版瀏覽器的相容性
  5. 持續監控並優化壓縮效能

記住,壓縮只是網站效能優化的一環,結合快取策略、CDN 部署、圖片優化等技術,才能達到最佳的效能表現。

參考資源

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