Bir web sayfasının hızını belirleyen en somut etkenlerden biri, tarayıcının indirmek zorunda olduğu bayt miktarıdır. HTML, CSS ve JavaScript dosyaları düz metin oldukları için içlerinde çok sayıda tekrar eden karakter, boşluk ve etiket barındırır; yani sıkıştırmaya son derece elverişlidirler. Sunucu bu dosyaları olduğu gibi göndermek yerine, gönderirken anlık olarak sıkıştırıp aktarır ve tarayıcı da alır almaz açar. Sonuç: aynı içerik çoğu zaman dörtte bir, hatta beşte bir boyuta iner. Kullanıcı için bu, ilk açılışın gözle görülür şekilde hızlanması demektir; sizin için ise daha az bant genişliği faturası anlamına gelir.
Nginx bu işi iki farklı algoritmayla yapabilir: yıllardır standart olan gzip ve Google'ın geliştirdiği, daha yüksek sıkıştırma oranı sunan brotli. Bu rehberde her ikisini de doğru biçimde nasıl etkinleştireceğinizi, hangi dosya tiplerini sıkıştırıp hangilerine dokunmamanız gerektiğini, sıkıştırma seviyesini nasıl ayarlayacağınızı ve HTTP/2 ile birlikte kullanıldığında ortaya çıkan performans kazanımını gerçek ölçümlerle göreceksiniz. Anlatım kıdemli bir sistem yöneticisinin bir müşterisine masabaşında anlattığı netlikte; her yapılandırma satırının neden orada olduğunu da açıklıyoruz.
Sıkıştırma Neden Bu Kadar İşe Yarar#
Sıkıştırmanın etkisini anlamak için önce hangi dosyaların sıkışabildiğini kavramak gerekir. Metin tabanlı içerik, yapısı gereği yüksek oranda tekrar barındırır. Bir HTML sayfasında <div class="...">, </div>, boşluklar ve girintiler onlarca kez geçer; bir CSS dosyasında margin, padding, color gibi anahtar kelimeler yüzlerce satırda tekrarlanır. Sıkıştırma algoritmaları tam olarak bu tekrarları yakalayıp kısa referanslarla değiştirir. Bu yüzden bir jQuery dosyası veya büyük bir CSS bütünü sıkıştırıldığında %70-80 küçülebilir.
Buna karşılık JPEG, PNG, WebP, MP4 gibi medya dosyaları zaten kendi içinde sıkıştırılmıştır. Bunları gzip veya brotli ile tekrar sıkıştırmaya çalışmak neredeyse hiç kazanç sağlamaz; hatta CPU harcayıp dosyayı bir-iki bayt büyütebilir bile. Bu yüzden ileride göreceğimiz gibi sıkıştırmayı yalnızca metin tiplerine uygularız. Aşağıdaki tablo, tipik dosya türlerinin sıkıştırmaya nasıl tepki verdiğini özetliyor.
| Dosya türü | Örnek boyut | Sıkıştırma sonrası | Kazanç |
|---|---|---|---|
| HTML (blog sayfası) | 90 KB | 18 KB | ~%80 |
| CSS (birleştirilmiş) | 220 KB | 34 KB | ~%84 |
| JavaScript (uygulama) | 480 KB | 130 KB | ~%73 |
| JSON API yanıtı | 120 KB | 15 KB | ~%88 |
| JPEG görsel | 340 KB | 339 KB | ~%0 |
| MP4 video | 12 MB | 12 MB | ~%0 |
Görüldüğü gibi asıl kazanç metin dosyalarında. Sunucunuzda henüz Nginx kurulu değilse, önce Ubuntu üzerinde Nginx kurulumu rehberini tamamlayıp buraya dönmenizi öneririm; buradaki tüm ayarlar çalışan bir Nginx üzerine eklenir.
Gzip'i Etkinleştirmek#
Gzip, Nginx ile birlikte dahili olarak gelir; ayrı bir modül kurmanıza gerek yoktur. Yapılandırmayı ya nginx.conf içindeki http {} bloğuna ya da düzenli tutmak için ayrı bir dosyaya yazabilirsiniz. Ayrı dosya yöntemini tavsiye ederim; hem okunabilir olur hem de gerektiğinde tek dosyayı devre dışı bırakabilirsiniz.
sudo nano /etc/nginx/conf.d/gzip.conf
Aşağıdaki yapılandırmayı bu dosyaya yerleştirin. Her satırın anlamını hemen altında açıklıyorum:
# Gzip sıkıştırmasını aç
gzip on;
# Vekil sunucular ve CDN'ler için sıkıştırılmış yanıtın önbelleğe
# doğru alınmasını sağlar (Vary: Accept-Encoding başlığı ekler)
gzip_vary on;
# İstemci gzip desteklese bile bazı eski vekiller sorun çıkarır;
# "any" tüm vekil istekleri için de sıkıştırmayı etkinleştirir
gzip_proxied any;
# Sıkıştırma seviyesi (1-9). 5-6 arası boyut/CPU dengesi için idealdir
gzip_comp_level 6;
# Bu boyutun altındaki yanıtları sıkıştırma; küçük dosyalarda
# sıkıştırma başlığı ve CPU maliyeti kazançtan büyük olur
gzip_min_length 256;
# Sıkıştırılacak MIME tipleri (text/html varsayılan olarak dahildir)
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/json
application/xml
application/rss+xml
application/atom+xml
application/vnd.ms-fontobject
application/x-font-ttf
font/opentype
image/svg+xml
image/x-icon;
Burada dikkat edilmesi gereken birkaç ince nokta var. gzip_types listesine text/html yazmanıza gerek yoktur; Nginx onu her zaman otomatik olarak sıkıştırır, hatta listeye eklerseniz "duplicate MIME type" uyarısı verebilir. Görselleri kasıtlı olarak dışarıda bıraktık; tek istisna image/svg+xml, çünkü SVG aslında XML tabanlı bir metin biçimidir ve gayet iyi sıkışır. Dosyayı kaydettikten sonra yapılandırmayı test edip Nginx'i yeniden yükleyin:
sudo nginx -t
sudo systemctl reload nginx
nginx -t komutu yapılandırmada sözdizimi hatası olup olmadığını denetler; reload ise mevcut bağlantıları koparmadan yeni ayarları devreye alır. Servis yönetimi konusunda derinleşmek isterseniz systemd servis yönetimi rehberindeki systemctl bölümü de işinize yarar.
Sıkıştırma Seviyesi ve min_length Dengesi#
gzip_comp_level değeri 1 ile 9 arasında bir sayıdır. Sayı büyüdükçe dosya daha çok küçülür ama sıkıştırma daha çok CPU harcar. Buradaki püf nokta, kazancın seviye arttıkça giderek azalmasıdır: seviye 1'den 6'ya geçmek çıktıyı belirgin biçimde küçültürken, 6'dan 9'a çıkmak çoğu zaman yalnızca %1-2 ek kazanç sağlar, buna karşılık işlemci yükünü kayda değer biçimde artırır.
Aşağıdaki tablo, 480 KB'lık bir JavaScript dosyasında tipik bir sonucu gösteriyor. Değerler dosya içeriğine göre değişir ama eğilim her zaman aynıdır:
| gzip_comp_level | Çıktı boyutu | Göreli CPU |
|---|---|---|
| 1 | 158 KB | 1x |
| 4 | 138 KB | 1.6x |
| 6 | 130 KB | 2.4x |
| 9 | 127 KB | 5x |
Pratikte tavsiyem: yoğun trafikli bir sitede, dosyalar her istekte yeniden sıkıştırılıyorsa seviye 5 veya 6 en mantıklı dengedir. Statik dosyaları önceden sıkıştırıp diske kaydediyorsanız (birazdan brotli bölümünde göreceğimiz gibi) seviyeyi rahatça 9'a çekebilirsiniz, çünkü sıkıştırma bir kez yapılır ve sonuç tekrar tekrar sunulur.
gzip_min_length ise çok küçük yanıtları sıkıştırma dışında bırakır. Birkaç yüz baytlık bir yanıtı sıkıştırmak, hem gzip'in eklediği başlık yükü hem de harcanan CPU yüzünden çoğu zaman zarar getirir. 256 bayt makul bir alt sınırdır; bunu 1024'e kadar yükseltmek de yaygın bir tercihtir.
Brotli Modülünü Kurmak#
Brotli, gzip'e göre metin dosyalarında tipik olarak %15-25 daha iyi sıkıştırma sunar. Ancak brotli, Nginx'in Ubuntu deposundaki paketiyle birlikte gelmez; modül olarak eklemeniz gerekir. En temiz yol, libnginx-mod-http-brotli veya benzeri hazır modül paketini kurmaktır. Dağıtımınıza göre paket adı değişebilir:
sudo apt update
sudo apt install libnginx-mod-http-brotli -y
Bu paket, dinamik modül olarak brotli'yi kurar ve genellikle /etc/nginx/modules-enabled/ altına gerekli load_module satırlarını otomatik ekler. Kurulumdan sonra modüllerin yüklendiğini doğrulayın:
ls /etc/nginx/modules-enabled/
sudo nginx -t
Eğer dağıtımınızda hazır paket yoksa, modülü kaynaktan derlemeniz gerekir. Bu, çalışan Nginx sürümünüzle birebir aynı kaynağı gerektirir; sürüm uyuşmazlığı modülün yüklenmemesine yol açar. Kaynaktan derleme özetle şöyledir:
# Gerekli araçlar
sudo apt install git gcc make libpcre3-dev zlib1g-dev libssl-dev -y
# Brotli kaynağını ve Nginx modülünü çek
git clone --recurse-submodules https://github.com/google/ngx_brotli.git
cd ngx_brotli && git submodule update --init && cd ..
# Çalışan Nginx ile aynı sürümü indir (örnek: 1.24.0)
wget https://nginx.org/download/nginx-1.24.0.tar.gz
tar zxf nginx-1.24.0.tar.gz
cd nginx-1.24.0
# Dinamik modül olarak derle
./configure --with-compat --add-dynamic-module=../ngx_brotli
make modules
# Derlenen .so dosyalarını modül dizinine kopyala
sudo cp objs/ngx_http_brotli_*.so /usr/lib/nginx/modules/
Derlemede --with-compat bayrağı kritiktir; modülün mevcut Nginx ikili dosyanızla uyumlu olmasını sağlar. Kaynaktan derleme kulağa zahmetli geliyorsa, çoğu yönetimli barındırma ortamında brotli zaten hazır gelir; sunucu yönetimi hizmetimizde bu tür modül kurulumlarını sizin yerinize biz yapıyoruz.
Brotli'yi Yapılandırmak: Statik ve Dinamik#
Modül yüklendikten sonra brotli'nin kendi yapılandırmasını yazacağız. Burada iki farklı çalışma biçimi vardır ve ikisini birlikte kullanmak en verimlisidir. Yeni bir yapılandırma dosyası açın:
sudo nano /etc/nginx/conf.d/brotli.conf
# Dinamik brotli: yanıtı istek anında sıkıştırır
brotli on;
# Sıkıştırma seviyesi (0-11). Dinamik için 4-6 idealdir
brotli_comp_level 5;
# Sıkıştırılacak MIME tipleri (gzip ile aynı mantık)
brotli_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/json
application/xml
application/rss+xml
application/atom+xml
image/svg+xml
font/opentype
application/vnd.ms-fontobject;
# Statik brotli: .br uzantılı önceden sıkıştırılmış dosya varsa onu sun
brotli_static on;
Buradaki iki direktifin farkını anlamak çok önemli. brotli on (dinamik brotli) her istekte yanıtı canlı olarak sıkıştırır; bu, dinamik içerik (WordPress çıktısı, API yanıtları) için gereklidir. brotli_static on ise farklı çalışır: diskte örneğin app.js dosyasının yanında app.js.br adında önceden sıkıştırılmış bir sürüm varsa, Nginx bunu hiç CPU harcamadan doğrudan sunar. Bu, statik varlıklar için ideal yöntemdir; sıkıştırmayı bir kez, en yüksek seviyede (11) build aşamasında yaparsınız ve sonuç sonsuza dek yeniden kullanılır.
Statik .br dosyalarını üretmek için build sürecinize bir adım ekleyebilirsiniz:
# Bir dizindeki tüm statik varlıkları en yüksek seviyede sıkıştır
find /var/www/site/dist -type f \
\( -name "*.js" -o -name "*.css" -o -name "*.svg" -o -name "*.html" \) \
-exec brotli -f -q 11 {} \;
Bu komut her dosyanın yanına .br sürümünü bırakır. brotli_static on sayesinde Nginx, brotli destekleyen tarayıcıya otomatik olarak .br sürümünü sunar; desteklemeyene ise orijinali veya dinamik gzip çıktısını verir. Bu strateji özellikle WordPress hız optimizasyonu tarafında birleştirilmiş varlık dosyalarında ciddi fark yaratır.
HTTP/2 ile Birlikte Kullanmak#
Sıkıştırma, aktarılan içeriğin boyutunu küçültür; HTTP/2 ise aynı bağlantı üzerinden birden çok dosyanın paralel ve daha az gecikmeyle taşınmasını sağlar. İkisi birbirini tamamlar. Modern bir sitede her ikisini de açık tutmak gerekir. HTTP/2'yi etkinleştirmek için server bloğunuzdaki listen satırını güncellersiniz — bunun için TLS (HTTPS) zorunludur, çünkü tarayıcılar HTTP/2'yi yalnızca şifreli bağlantı üzerinde kullanır.
server {
listen 443 ssl;
http2 on;
server_name ornek-alan-adi.com;
ssl_certificate /etc/letsencrypt/live/ornek-alan-adi.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ornek-alan-adi.com/privkey.pem;
# gzip.conf ve brotli.conf http bloğunda açık olduğu için
# bu server bloğunda otomatik geçerlidir
root /var/www/ornek-alan-adi/dist;
index index.html;
}
Not: Nginx 1.25.1 ve sonrasında HTTP/2, yukarıdaki gibi ayrı http2 on; direktifiyle açılır; daha eski sürümlerde listen 443 ssl http2; yazımı kullanılır. HTTPS henüz kurulu değilse, ücretsiz bir sertifikayla başlamak için Let's Encrypt SSL tarafına bakabilirsiniz. Sıkıştırma + HTTP/2 + doğru önbellek başlıkları üçlüsü, sayfa hızını en çok etkileyen sunucu tarafı ayarlarıdır ve doğrudan SEO performansınıza yansır, çünkü sayfa hızı arama sıralamasında ölçülen bir sinyaldir.
Kazancı Gerçekten Ölçmek#
"Açtım ama işe yaradı mı?" sorusunun tek doğru cevabı ölçümdür. Bir yanıtın gerçekten sıkıştırılıp sıkıştırılmadığını curl ile saniyeler içinde doğrulayabilirsiniz. Önce brotli isteyerek deneyin:
curl -s -H "Accept-Encoding: br" -I https://ornek-alan-adi.com/style.css
Yanıt başlıklarında content-encoding: br satırını görüyorsanız brotli çalışıyor demektir. Aynısını gzip için de deneyin:
curl -s -H "Accept-Encoding: gzip" -I https://ornek-alan-adi.com/style.css
Bu kez content-encoding: gzip görmelisiniz. Sıkıştırılmış ve sıkıştırılmamış boyutu doğrudan karşılaştırmak için dosyayı iki kez indirip boyutlarını ölçebilirsiniz:
# Sıkıştırmasız gerçek boyut
curl -s https://ornek-alan-adi.com/app.js | wc -c
# Brotli ile aktarılan boyut
curl -s -H "Accept-Encoding: br" https://ornek-alan-adi.com/app.js --compressed -o /dev/null -w "%{size_download} bayt\n"
Tipik bir tek sayfa uygulamasında (SPA) bu ölçümler şöyle bir tablo ortaya çıkarır. Aradaki fark, doğrudan kullanıcının indirme süresine yansır:
| Varlık | Ham | Gzip (6) | Brotli (11 statik) |
|---|---|---|---|
| vendor.js | 512 KB | 168 KB | 142 KB |
| main.css | 190 KB | 31 KB | 26 KB |
| index.html | 42 KB | 9 KB | 7 KB |
| Toplam | 744 KB | 208 KB | 175 KB |
Bu örnekte toplam aktarım 744 KB'tan 175 KB'a, yani dörtte birinin altına indi. Yavaş bir mobil bağlantıda bu, birkaç saniyelik gecikme farkı demektir. Tarayıcının Geliştirici Araçları'ndaki Network sekmesi de her isteğin "Size" (aktarılan) ve "Content" (açılmış) sütunlarını yan yana göstererek aynı kazancı gözle görülür kılar. Ölçüm alışkanlığı, "ayarladım geçtim" tuzağına düşmenizi önler; bir güncelleme sonrası sıkıştırmanın sessizce devre dışı kaldığını yalnızca ölçerek fark edebilirsiniz.
Sık Yapılan Hatalar#
Sıkıştırma yapılandırmasında en sık karşılaşılan sorun, brotli modülünün sürüm uyuşmazlığı yüzünden yüklenmemesidir. nginx -t çıktısında "module ... is not binary compatible" gibi bir hata görürseniz, modülü çalışan Nginx sürümünüzle aynı kaynaktan yeniden derlemeniz gerekir. Bu yüzden hazır paket kullanmak mümkünse her zaman tercih edilir.
İkinci sık hata, bir vekil veya CDN katmanının sıkıştırmayı gölgelemesidir. Örneğin Nginx'in önünde Cloudflare varsa, Cloudflare kendi sıkıştırmasını uygulayabilir ve sizin content-encoding başlığınız CDN tarafından değiştirilebilir. Bu durumda ölçümü doğrudan origin sunucusuna (CDN'i atlayarak) yaparak Nginx'in payını izole etmelisiniz. Üçüncü olarak, gzip_types veya brotli_types listesine text/html eklemek gereksizdir ve çift tanım uyarısı üretir; HTML her zaman otomatik sıkıştırılır.
Son bir uyarı: sıkıştırmayı görsel ve video tiplerine uygulamaya çalışmak yalnızca CPU israfıdır. Kütüphanenizde bu tipler types listesinde yer almamalıdır. Bant genişliği ve kaynak yönetimi bir bütündür; sıkıştırmayı doğru kurduktan sonra önbellekleme ve doğru Cache-Control başlıkları ile birleştirdiğinizde asıl büyük kazancı elde edersiniz.
Sıkça Sorulan Sorular#
Gzip ve brotli'yi aynı anda açabilir miyim?#
Evet, hatta önerilen yöntem tam olarak budur. Nginx, her isteği yapan tarayıcının Accept-Encoding başlığına bakar; brotli destekleyen modern tarayıcılara brotli sürümünü, yalnızca gzip destekleyen eski istemcilere gzip sürümünü, hiçbirini desteklemeyene ise ham dosyayı sunar. İki yapılandırmayı birlikte tutmak, hem en yüksek sıkıştırma oranını hem de en geniş tarayıcı uyumluluğunu aynı anda sağlar; birinin diğerine bir zararı yoktur.
Sıkıştırma seviyesini kaça ayarlamalıyım?#
Dinamik olarak her istekte sıkıştırılan içerik için gzip'te 5-6, brotli'de 4-6 en dengeli aralıktır. Bunun üstüne çıkmak boyutu çok az küçültürken CPU yükünü belirgin biçimde artırır. Statik dosyaları önceden .br veya .gz olarak diske sıkıştırıyorsanız durum farklıdır; orada sıkıştırma bir kez yapılıp sonuç tekrar tekrar sunulacağı için seviyeyi rahatça en yükseğe (gzip 9, brotli 11) çekebilirsiniz.
Görselleri de sıkıştırmalı mıyım?#
Hayır. JPEG, PNG, WebP, GIF ve MP4 gibi medya dosyaları kendi biçimleri içinde zaten sıkıştırılmıştır; bunları gzip veya brotli ile tekrar sıkıştırmaya çalışmak neredeyse hiç kazanç getirmez, sadece CPU harcar. Tek istisna SVG dosyalarıdır; SVG aslında XML tabanlı bir metin biçimi olduğu için gayet iyi sıkışır ve image/svg+xml tipini listenize eklemek mantıklıdır.
Sıkıştırmanın çalıştığını nasıl doğrularım?#
En pratik yöntem curl -H "Accept-Encoding: br" -I https://siteniz.com/dosya.css komutunu çalıştırıp yanıt başlıklarında content-encoding: br satırını aramaktır. Aynısını gzip için de deneyebilirsiniz. Alternatif olarak tarayıcının Geliştirici Araçları'ndaki Network sekmesinde her isteğin aktarılan boyutu ile açılmış boyutunu yan yana görebilir, ikisi arasındaki farkı doğrudan gözlemleyebilirsiniz.
Brotli neden Nginx ile hazır gelmiyor?#
Nginx'in çekirdeği olabildiğince yalın tutulur ve brotli, çekirdeğe dahil olmayan bir üçüncü taraf modülüdür. Bu yüzden ya libnginx-mod-http-brotli gibi hazır bir modül paketi kurmanız ya da modülü çalışan Nginx sürümünüzle aynı kaynaktan derlemeniz gerekir. Yönetimli barındırma ortamlarının çoğunda ise brotli önceden kurulu gelir, dolayısıyla siz sadece yapılandırmayı yazarsınız.
HTTP/2 açık değilse sıkıştırma yine de işe yarar mı?#
Evet. Sıkıştırma ve HTTP/2 birbirinden bağımsız iki iyileştirmedir; sıkıştırma aktarılan bayt sayısını düşürür, HTTP/2 ise aynı bağlantı üzerinden çoklu dosyayı daha verimli taşır. HTTP/2 kapalı olsa bile gzip veya brotli aktarım boyutunu düşürerek sayfayı hızlandırır. Yine de en iyi sonucu ikisini birlikte, HTTPS üzerinden kullanınca alırsınız; bu üçlü modern bir sitenin standart yapılandırmasıdır.
Kapanış#
Gzip ve brotli sıkıştırma, tek bir yapılandırma dosyasıyla açabileceğiniz ama etkisi doğrudan sayfa hızına ve bant genişliği maliyetine yansıyan, düşük emek-yüksek getiri iyileştirmelerinin başında gelir. Metin tabanlı varlıklarınızı sıkıştırıp görselleri listeden çıkararak, sıkıştırma seviyesini CPU dengesine göre ayarlayarak ve mümkünse statik .br dosyalarını build aşamasında üreterek hem kullanıcı deneyimini hem de altyapı verimliliğini aynı anda iyileştirirsiniz. Her değişikliğin ardından curl veya tarayıcı araçlarıyla ölçüm yapmayı alışkanlık haline getirin; böylece kazancın gerçek olduğundan ve zamanla sessizce kaybolmadığından emin olursunuz.
Bu tür sunucu tarafı optimizasyonları için tam kontrole sahip bir ortama ihtiyacınız varsa, VDS sunucularımıza veya sanal sunucularımıza göz atabilir; modül kurulumu, brotli derlemesi ve performans ayarlarını uzman ekibimize bırakmak isterseniz sunucu yönetimi hizmetimizden yararlanabilirsiniz. Yeni bir projeye başlıyorsanız, hızlı ve optimize web hosting paketlerimiz de sıkıştırma dahil pek çok performans ayarını sizin için hazır olarak sunar.