تفعيل Brotli في Nginx بيقلّل حجم الـ bundle المنقول للمستخدم 20 إلى 25 بالمية فوق ما بيعمله gzip، بدون أي تغيير في الكود. النتيجة: TTFB أقل، LCP أسرع، وفاتورة CDN أقل بمئات الدولارات في الشهر على المواقع المتوسطة الحجم.
المشكلة باختصار
الـ gzip بيضغط استجابات HTTP من سنة 1992، وكل المتصفحات بتدعمه. المشكلة إنه واقف عند نسبة ضغط حوالي 70 بالمية للنصوص. Brotli — اللي طلع من Google سنة 2015 — بيوصل لـ 80 بالمية أو أكثر على نفس الملف، لأن عنده dictionary مدمج بـ 120KB من أنماط الـ web الشائعة. لو سيرفرك بيخدم 10TB JavaScript شهريًا، الفرق بين gzip و brotli بيتحوّل لـ 2TB بندويث موفّر، أو ~170 دولار شهريًا على CloudFront بأسعار 2025.
الـ Brotli مدعوم في 96.8 بالمية من المتصفحات حسب Can I Use في 2026. مفيش سبب تقني تستمر فيه على gzip لوحده.
مثال للمبتدئين: ليه نسبة الضغط بتفرق فعلاً؟
تخيّل إنك بتشحن كتاب في صندوق. الـ gzip بيلف الكتاب مرتين بشريط لاصق ويحطه في صندوق صغير. الـ brotli بيعرف إن صفحات الكتاب فيها كلمات بتتكرّر زي function و const و <div>، فبيستبدلها برمز مختصر قبل ما يلفّه. النتيجة: نفس الكتاب بيوصل في صندوق أصغر بـ 25 بالمية، والمستلم بيعرف يفك الرمز لأن نفس القاموس عنده.
على HTTP، اللي بيحصل بالظبط: المتصفح بيبعت Accept-Encoding: gzip, br في كل request، والسيرفر بيختار أحسن واحد متوفر. لو ما عملتش enable لـ brotli في Nginx، السيرفر بيرجع gzip بشكل افتراضي حتى لو المتصفح كان مستعد لـ brotli، والـ payload بيكون أكبر بدون داعي.
التعريف العلمي الدقيق
Brotli خوارزمية ضغط lossless مبنية على LZ77 و Huffman coding، بس مع context modeling من الدرجة الثانية وقاموس ثابت بـ 13,504 كلمة شائعة في الـ web (HTML tags، CSS properties، JavaScript keywords، إلخ). الـ RFC 7932 بيحدّد التفاصيل. على مستوى الضغط الأعلى (level 11)، Brotli بيعطي نسبة ضغط أحسن من gzip بحوالي 14 إلى 25 بالمية للنصوص و~21 بالمية للـ HTML تحديدًا، حسب قياس Google لـ Alexa Top 1000.
الافتراض المهم: Brotli مفيد للـ text-based content فقط. الصور المضغوطة مسبقًا (JPG، PNG، WebP) والفيديو (MP4) ما هتستفيدش من ضغط إضافي.
تفعيل Brotli في Nginx خطوة بخطوة
- ثبّت module الـ
ngx_brotli. مش متضمن في Nginx افتراضيًا، لكن في Nginx Plus وفي حزم Ubuntu 22.04+ متاح كـlibnginx-mod-http-brotli-staticوlibnginx-mod-http-brotli-filter. - عدّل ملف
nginx.confبإضافة الإعدادات اللي تحت في الـhttpblock. - فعّل static precompression: اضغط ملفاتك مرة واحدة وقت الـ build بدل ما السيرفر يضغطها مع كل request.
- تحقّق من الـ response headers بـ
curl -I -H "Accept-Encoding: br" https://yoursite.com/app.jsوشوفContent-Encoding: br.
# /etc/nginx/conf.d/brotli.conf
brotli on;
brotli_comp_level 6; # runtime: 4-6 توازن جيد بين CPU والنسبة
brotli_static on; # خد ملفات .br المضغوطة مسبقًا لو موجودة
brotli_min_length 1024; # ما تضغطش ملفات أقل من 1KB
brotli_types
text/plain
text/css
text/xml
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml
font/woff
font/woff2;
# gzip كـ fallback للمتصفحات اللي ما بتدعمش brotli
gzip on;
gzip_comp_level 6;
gzip_static on;
gzip_min_length 1024;
gzip_vary on;
gzip_types
text/plain text/css application/json application/javascript
application/xml text/xml application/xml+rss image/svg+xml;
للـ static precompression، ضيف خطوة في الـ build pipeline تعمل ملفات .br و .gz جنب الأصول:
# اضغط ملفات الـ dist مرة واحدة بأقصى مستوى
find ./dist -type f \
\( -name "*.js" -o -name "*.css" -o -name "*.html" -o -name "*.svg" -o -name "*.json" \) \
-exec brotli -k -q 11 {} \; \
-exec gzip -k -9 {} \;
# تحقق إن الملفات اتعملت
ls -lh ./dist/assets/main.js ./dist/assets/main.js.br ./dist/assets/main.js.gz
أرقام قبل وبعد من قياس فعلي
قياس على bundle React بحجم أصلي 850KB (vendors.js + main.js + styles.css)، السيرفر Nginx 1.24 على Ubuntu 22.04، CPU AMD EPYC 4 cores:
- بدون ضغط: 850KB، TTFB متوسط 240ms على 4G.
- gzip level 6 (dynamic): 248KB، نسبة ضغط 70.8 بالمية.
- brotli level 6 (dynamic): 198KB، نسبة ضغط 76.7 بالمية، CPU زيادة 8 بالمية على نفس الحمل.
- brotli level 11 (static precompressed): 176KB، نسبة ضغط 79.3 بالمية، CPU زيادة صفر لأن الضغط حصل في الـ build.
الفرق العملي: على 10 مليون hits شهريًا، gzip → brotli static = 720GB بندويث موفّر. على CloudFront في US-East بسعر 0.085 دولار/GB، ده ~61 دولار شهريًا من ضغط واحد على ملف JS.
الـ Trade-offs اللي لازم تعرفها قبل ما تفعّل
الضغط مش ببلاش، وكل تحسين معاه ثمن:
- CPU وقت dynamic compression: brotli level 6 بيستهلك ~25 بالمية CPU زيادة عن gzip level 6 على نفس عدد الـ requests. لو السيرفر بتاعك بيخدم 5K RPS وعنده hot CPU أصلًا، dynamic brotli ممكن يخلّيه يلهث. الحل: استخدم static precompression للأصول الثابتة، وdynamic للـ API responses الحيّة فقط.
- زمن الـ build بيزيد: brotli -q 11 بطيء جدًا، حوالي 30 ثانية لـ 1MB JS على core واحد. شغّله بـ
parallelأو على CI runner منفصل عن خطوة الـ tests. - المتصفحات القديمة: IE11 ومتصفحات قبل 2016 ما بتدعمش brotli أصلًا. الحل:
gzip_static onكـ fallback تلقائي. - HTTPS فقط: Chrome وFirefox ما بيبعتوش
Accept-Encoding: brإلا على HTTPS. لو سيرفرك بدون TLS، Brotli مش هيشتغل أصلًا. ده قرار أمني من المتصفحات لمنع content injection على الشبكات غير المشفّرة.
متى لا تستخدم Brotli
الضغط مش حلّ سحري لكل ملف. لا تفعّله في الحالات دي:
- محتوى مضغوط مسبقًا: ملفات JPG، PNG، WebP، MP4، PDF، ZIP بالفعل مضغوطة. ضغطها تاني بيهدر CPU وممكن يكبّر الحجم بسبب overhead الـ headers.
- Real-time streaming: SSE وWebSocket frames صغيرة. ضغطها بيضيف latency أكثر من ما يوفر، وممكن يعطّل الـ streaming behavior.
- ملفات أصغر من 1KB: overhead الـ compression headers أكبر من الفائدة. خليّ
brotli_min_length 1024. - API بـ 1000+ RPS على CPU محدود: dynamic brotli ممكن يخلّي الـ CPU 100 بالمية بسرعة. استخدم gzip للـ dynamic، أو احطّ CDN قدامه يتولّى الضغط.
الخطوة التالية
افتح موقعك في Chrome DevTools → Network → اعمل reload. اختار أكبر ملف JS وشوف Content-Encoding في الـ Response Headers. لو لقيته gzip، انسخ الكود اللي فوق في nginx.conf، اعمل nginx -t && systemctl reload nginx، وأعد القياس. لازم تشوف br ووفر فوري في حجم الـ Transfer. لو فرق النسبة أقل من 20 بالمية، ده معناه إن أصولك مش مضغوطة مسبقًا — ضيف خطوة الـ static precompression في الـ build وقيس تاني.
مصادر
- RFC 7932: Brotli Compressed Data Format Specification — IETF (2016)
- Google Developers Blog: "Introducing Brotli: a new compression algorithm for the internet" — قياس على Alexa Top 1000
- توثيق Nginx:
ngx_brotlimodule README على GitHub (google/ngx_brotli) - توثيق Nginx الرسمي:
ngx_http_gzip_static_moduledirectives - Can I Use: Brotli support — 96.8 بالمية global browser coverage في 2026
- AWS CloudFront pricing — تحديث يناير 2026 لمنطقة US-East
- Cloudflare Blog: "Results of experimenting with Brotli for dynamic web content"