Nginx Gzip ve Brotli Sıkıştırma Yapılandırması

Web sitenizin yüklenme hızı, hem kullanıcı deneyimi hem de SEO açısından kritik öneme sahip. Sunucudan tarayıcıya giden her kilobayt, özellikle mobil kullanıcılar için değerli. İşte bu noktada sıkıştırma devreye giriyor. Nginx üzerinde Gzip ve Brotli yapılandırması yaparak sayfa ağırlığını ciddi ölçüde düşürebilir, sunucu bant genişliği kullanımını azaltabilir ve kullanıcılarınıza daha hızlı bir deneyim sunabilirsiniz. Bu yazıda hem Gzip hem de Brotli’yi gerçek dünya senaryolarıyla nasıl yapılandıracağınızı adım adım ele alacağız.

Gzip ve Brotli Nedir, Neden İkisi Birden?

Gzip, onlarca yıldır web sunucularında kullanılan, evrensel tarayıcı desteğine sahip bir sıkıştırma algoritmasıdır. Hemen her tarayıcı Gzip’i anlar ve destekler. Bu yüzden geriye dönük uyumluluk açısından vazgeçilmezdir.

Brotli ise Google tarafından 2015 yılında geliştirilen ve Gzip’e kıyasla çok daha iyi sıkıştırma oranları sunan modern bir algoritmadır. Özellikle metin tabanlı içeriklerde Gzip’e göre yüzde 20-26 daha iyi sıkıştırma sağlar. Chrome, Firefox, Edge ve Safari gibi modern tarayıcıların tamamı Brotli’yi destekler.

Peki neden ikisini birden yapılandıralım? Çünkü tarayıcı, sunucuya istek gönderirken Accept-Encoding başlığıyla hangi sıkıştırma yöntemlerini desteklediğini belirtir. Nginx, bu başlığa bakarak en uygun algoritmayı seçer. Modern tarayıcılara Brotli, eski tarayıcılara Gzip sunar. Böylece hem maksimum performans hem de tam uyumluluk elde edersiniz.

Ön Koşullar ve Sistem Kontrolü

Gzip, Nginx’in standart kurulumunda hazır gelir. Brotli içinse ngx_brotli modülü gereklidir. Başlamadan önce sisteminizin durumunu kontrol edelim.

# Nginx versiyonunu ve derlenmiş modülleri kontrol et
nginx -V 2>&1 | grep -o with-[a-z_]* | sort

# Brotli modülünün yüklü olup olmadığını kontrol et
nginx -V 2>&1 | grep -i brotli

# Mevcut Nginx konfigürasyonunu test et
nginx -t

# Sistemdeki Nginx paket bilgisini görüntüle
dpkg -l nginx* 2>/dev/null || rpm -qa | grep nginx

Eğer Brotli modülü çıktıda görünmüyorsa iki seçeneğiniz var: ya Brotli desteğiyle önceden derlenmiş bir Nginx paketi kullanırsınız ya da Nginx’i kaynak koddan kendiniz derlersiniz.

Brotli Modülünü Yükleme

Ubuntu/Debian Sistemlerde

Ubuntu ve Debian üzerinde libnginx-mod-http-brotli-filter ve libnginx-mod-http-brotli-static paketleri çoğu zaman resmi depolardan veya Nginx’in kendi deposundan gelmez. En pratik yol nginx.org’un resmi deposunu kullanmaktır.

# Nginx resmi deposunu ekle (Ubuntu 22.04 için)
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor 
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] 
http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" 
    | sudo tee /etc/apt/sources.list.d/nginx.list

sudo apt update
sudo apt install nginx

# Brotli için dinamik modül paketini yükle
sudo apt install libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-static

CentOS/RHEL/Rocky Linux Sistemlerde

# EPEL ve Nginx resmi reposunu ekle
sudo dnf install epel-release
sudo dnf install nginx

# Brotli modülünü derlemek için gerekli bağımlılıklar
sudo dnf install gcc gcc-c++ make cmake git pcre-devel openssl-devel 
    zlib-devel gd-devel libxslt-devel perl-devel perl-ExtUtils-Embed 
    GeoIP-devel brotli-devel

# ngx_brotli modülünü klonla
git clone --recurse-submodules https://github.com/google/ngx_brotli.git /tmp/ngx_brotli

# Nginx kaynak kodunu indir (mevcut versiyonunuzla eşleştirin)
NGINX_VERSION=$(nginx -v 2>&1 | grep -o '[0-9.]*$')
wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz -P /tmp/
cd /tmp && tar xzf nginx-${NGINX_VERSION}.tar.gz

# Sadece modülü derle (--add-dynamic-module)
cd /tmp/nginx-${NGINX_VERSION}
./configure --with-compat --add-dynamic-module=/tmp/ngx_brotli
make modules

# Derlenen modülleri kopyala
sudo cp objs/ngx_http_brotli_filter_module.so /etc/nginx/modules/
sudo cp objs/ngx_http_brotli_static_module.so /etc/nginx/modules/

Nginx Ana Yapılandırmasına Modülleri Yükleme

Brotli modüllerini derleme ya da paket kurulumu yoluyla aldıktan sonra nginx.conf dosyasına yüklemeniz gerekir.

# /etc/nginx/nginx.conf dosyasının en üstüne ekleyin
load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

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

    # Gzip yapılandırması
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_min_length 256;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml
        application/xml+rss
        application/atom+xml
        image/svg+xml
        font/truetype
        font/opentype
        application/vnd.ms-fontobject;

    # Brotli yapılandırması
    brotli on;
    brotli_comp_level 6;
    brotli_static on;
    brotli_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml
        application/xml+rss
        application/atom+xml
        image/svg+xml
        font/truetype
        font/opentype
        application/vnd.ms-fontobject;

    include /etc/nginx/conf.d/*.conf;
}

Yapılandırma Parametrelerinin Detaylı Açıklaması

Gzip Parametreleri

  • gzip on: Gzip sıkıştırmayı etkinleştirir. Varsayılan olarak kapalıdır.
  • gzip_vary on: Yanıt başlığına Vary: Accept-Encoding ekler. CDN ve proxy’lerin sıkıştırılmış ile sıkıştırılmamış yanıtları ayrı önbelleğe alması için şarttır.
  • gzip_proxied any: Proxy üzerinden gelen tüm istekler için sıkıştırmayı etkinleştirir. expired, no-cache, no-store, private, auth gibi değerler de kullanılabilir.
  • gzip_comp_level 6: Sıkıştırma seviyesidir. 1 en hızlı (az sıkıştırma), 9 en yavaş (çok sıkıştırma) anlamına gelir. 6, hız ve sıkıştırma dengesi için ideal değerdir. Production’da 4-6 arası önerilir.
  • gzip_buffers 16 8k: Sıkıştırma için kullanılacak tampon sayısını ve boyutunu belirtir. 16 adet 8KB tampon kullanır.
  • gzip_http_version 1.1: Minimum HTTP versiyonu belirtir. HTTP/1.0 ile gzip kullanımında sorunlar çıkabilir, 1.1 güvenli seçenektir.
  • gzip_min_length 256: Byte cinsinden minimum yanıt boyutunu belirtir. Bundan küçük yanıtlar sıkıştırılmaz. Çok küçük dosyaları sıkıştırmak zaman kaybı olabilir.
  • gzip_types: Sıkıştırılacak MIME tiplerini listeler. text/html her zaman dahildir, tekrar yazmanıza gerek yok.

Brotli Parametreleri

  • brotli on: Dinamik Brotli sıkıştırmayı etkinleştirir. İstekler gerçek zamanlı olarak sıkıştırılır.
  • brotli_comp_level 6: Sıkıştırma seviyesi. 0-11 arası değer alır. Yüksek değerler daha iyi sıkıştırma ama daha fazla CPU kullanımı demektir. 4-6 arası production için idealdir.
  • brotli_static on: Önceden sıkıştırılmış .br uzantılı dosyaları sunar. Eğer dosya.css.br varsa, dinamik sıkıştırma yapmak yerine bu dosyayı doğrudan sunar. CPU tasarrufu sağlar.
  • brotli_types: Gzip ile aynı mantık geçerlidir. Sıkıştırılacak MIME tipleri burada belirtilir.

Önceden Sıkıştırılmış Dosya Oluşturma (Pre-compression)

Dinamik sıkıştırma her istekte CPU kullanır. Statik varlıklar için deployment sırasında önceden sıkıştırılmış dosyalar oluşturmak çok daha verimlidir.

# Mevcut statik dosyaları Brotli ile sıkıştır
find /var/www/html -type f ( -name "*.css" -o -name "*.js" -o -name "*.html" -o -name "*.svg" ) | 
while read file; do
    brotli --best -f "$file" -o "${file}.br"
    echo "Sıkıştırıldı: ${file}.br"
done

# Gzip için de aynısını yap
find /var/www/html -type f ( -name "*.css" -o -name "*.js" -o -name "*.html" -o -name "*.svg" ) | 
while read file; do
    gzip -k -9 -f "$file"
    echo "Sıkıştırıldı: ${file}.gz"
done

# Boyut karşılaştırması
ls -lh /var/www/html/assets/app.js*

Bu scripti CI/CD pipeline’ınıza veya deploy hook’unuza ekleyerek her deployment’ta otomatik çalıştırabilirsiniz.

Gerçek Dünya Senaryosu: Nginx Virtual Host Yapılandırması

Tipik bir production web sitesi için örnek bir sanal host yapılandırması:

# /etc/nginx/conf.d/example.com.conf

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    root /var/www/example.com/public;
    index index.html index.php;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Statik varlıklar için agresif sıkıştırma ve uzun cache
    location ~* .(css|js|svg|xml)$ {
        gzip_static on;
        brotli_static on;
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Vary "Accept-Encoding";
    }

    # Fontlar için
    location ~* .(woff|woff2|ttf|eot|otf)$ {
        brotli_static on;
        gzip_static on;
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Access-Control-Allow-Origin "*";
    }

    # JSON API endpoint'leri için
    location /api/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

        # API yanıtlarını sıkıştır
        gzip on;
        gzip_min_length 1000;
        gzip_types application/json;

        brotli on;
        brotli_min_length 1000;
        brotli_types application/json;
    }

    # HTML dosyaları
    location / {
        try_files $uri $uri/ /index.html;
        gzip_static on;
        brotli_static on;
    }
}

Reverse Proxy Senaryosu

Nginx’i bir uygulama sunucusu (Node.js, Gunicorn, PHP-FPM) önünde reverse proxy olarak kullandığınızda, backend yanıtlarını da sıkıştırabilirsiniz.

# /etc/nginx/conf.d/nodejs-app.conf

upstream nodejs_backend {
    server 127.0.0.1:3000;
    keepalive 32;
}

server {
    listen 443 ssl http2;
    server_name app.example.com;

    # Global sıkıştırma ayarları bu server block için
    gzip on;
    gzip_vary on;
    gzip_proxied expired no-cache no-store private auth;
    gzip_comp_level 5;
    gzip_min_length 500;
    gzip_types
        text/plain
        text/css
        application/json
        application/javascript
        text/xml
        application/xml;

    brotli on;
    brotli_comp_level 5;
    brotli_types
        text/plain
        text/css
        application/json
        application/javascript
        text/xml
        application/xml;

    location / {
        proxy_pass http://nodejs_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_cache_bypass $http_upgrade;

        # Proxy buffer ayarları sıkıştırma verimliliğini etkiler
        proxy_buffering on;
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
    }
}

Sıkıştırmanın Test Edilmesi

Yapılandırmayı doğruladıktan sonra gerçekten çalışıp çalışmadığını test etmek kritik önem taşır.

# Nginx konfigürasyonunu test et ve yeniden yükle
nginx -t && systemctl reload nginx

# Gzip sıkıştırmasını test et
curl -H "Accept-Encoding: gzip" -I https://example.com/assets/app.css

# Brotli sıkıştırmasını test et
curl -H "Accept-Encoding: br" -I https://example.com/assets/app.css

# Her iki algoritmayı birden teklif et (tarayıcı gibi)
curl -H "Accept-Encoding: br, gzip, deflate" -I https://example.com/

# Sıkıştırılmış içeriği indir ve boyutu karşılaştır
curl -H "Accept-Encoding: gzip" -s -o /tmp/compressed.css https://example.com/assets/app.css
curl -s -o /tmp/uncompressed.css https://example.com/assets/app.css
ls -lh /tmp/compressed.css /tmp/uncompressed.css

# İçerik kodlamasını header'dan kontrol et
curl -H "Accept-Encoding: br, gzip" -sI https://example.com/ | grep -i "content-encoding"

Başarılı bir Brotli yanıtında content-encoding: br, Gzip yanıtında ise content-encoding: gzip görmeniz gerekir.

Sık Karşılaşılan Sorunlar ve Çözümleri

Çift Sıkıştırma Sorunu

Eğer backend uygulamanız (Node.js, Python vb.) zaten Gzip uyguluyorsa ve Nginx de üstüne sıkıştırma yapmaya çalışıyorsa, bozuk yanıtlar alabilirsiniz. Bunu engellemek için:

# Backend zaten sıkıştırmışsa Nginx tekrar sıkıştırmasın
location /api/ {
    proxy_pass http://backend;

    # Sıkıştırılmış yanıtları olduğu gibi geç
    proxy_set_header Accept-Encoding "";

    # Nginx tarafında sıkıştırmayı bu location için kapat
    gzip off;
    brotli off;
}

Vary Header Eksikliği ve CDN Sorunları

CDN veya proxy katmanı kullanıyorsanız Vary: Accept-Encoding header’ı olmazsa olmazdır. Aksi halde CDN, sıkıştırılmış bir yanıtı sıkıştırma desteklemeyen bir tarayıcıya sunabilir.

# Tüm sıkıştırılmış yanıtlara Vary header'ı ekle
add_header Vary "Accept-Encoding" always;

Küçük Dosyalar için Sıkıştırma Devre Dışı

100 byte’lık bir dosyayı sıkıştırmak hem işlemci kaynağı harcar hem de bazen dosyayı daha büyük yapabilir. gzip_min_length ve brotli_min_length değerlerini doğru ayarlayın. Genellikle 256-1000 byte arası bir değer idealdir.

Görüntü Dosyalarını Sıkıştırmayın

JPEG, PNG, WebP, GIF gibi görüntü formatları zaten kendi sıkıştırma algoritmalarını içerir. Bu dosyaları Gzip veya Brotli ile tekrar sıkıştırmak hem CPU kaynağı harcar hem de dosya boyutunu artırabilir. gzip_types ve brotli_types listelerinizde asla image/jpeg, image/png gibi tipler bulunmamalıdır.

Performans İzleme ve Log Analizi

Sıkıştırmanın ne kadar bant genişliği tasarrufu sağladığını ölçmek için Nginx log formatını özelleştirin.

# nginx.conf içinde log formatını zenginleştir
log_format compression '$remote_addr - $remote_user [$time_local] '
                       '"$request" $status $bytes_sent '
                       '"$http_referer" "$http_user_agent" '
                       'gzip_ratio=$gzip_ratio '
                       'encoding=$sent_http_content_encoding '
                       'length=$content_length';

access_log /var/log/nginx/access.log compression;

Log dosyasını analiz etmek için:

# Brotli kullanım oranını kontrol et
grep "encoding=br" /var/log/nginx/access.log | wc -l

# Gzip kullanım oranını kontrol et
grep "encoding=gzip" /var/log/nginx/access.log | wc -l

# Ortalama gzip sıkıştırma oranı
awk '/gzip_ratio=/ {split($NF,a,"="); sum+=a[2]; count++} END {print "Ortalama oran:", sum/count}' 
    /var/log/nginx/access.log

# Son 100 istek için encoding dağılımı
tail -100 /var/log/nginx/access.log | grep -oP 'encoding=K[^s]+' | sort | uniq -c

Güvenlik Notları

BREACH saldırısı, HTTPS üzerinde Gzip sıkıştırma ile birlikte ortaya çıkabilen bir side-channel saldırısıdır. Bu saldırıya karşı önlem olarak CSRF token’larının her istekte değiştirilmesi ve hassas sayfalar için sıkıştırmanın devre dışı bırakılması önerilir.

# Hassas sayfalar için sıkıştırmayı devre dışı bırak
location /admin/ {
    gzip off;
    brotli off;
    # diğer ayarlar...
}

location /account/ {
    gzip off;
    brotli off;
}

Sonuç

Nginx üzerinde Gzip ve Brotli yapılandırması, düşük maliyetli ama yüksek etkili bir performans optimizasyonudur. Doğru yapılandırıldığında metin tabanlı varlıklarda yüzde 60-80 boyut azalması elde edebilirsiniz. Bunu pratiğe dökersek; 500KB’lık bir JavaScript dosyası, Brotli ile 100-150KB’a kadar inebilir. Bu, özellikle mobil kullanıcılar için sayfa yükleme süresine doğrudan yansır.

Önerilen yaklaşım şu şekilde özetlenebilir: Modern tarayıcılar için Brotli, eski tarayıcılar için Gzip’i aktif tutun, statik varlıklar için deployment sürecinde önceden sıkıştırılmış dosyalar hazırlayın, brotli_static on ve gzip_static on direktiflerini kullanarak CPU tasarrufu sağlayın, görüntü ve video dosyalarını asla sıkıştırma listesine dahil etmeyin ve CDN kullanıyorsanız Vary: Accept-Encoding header’ının doğru iletildiğinden emin olun.

Bu yapılandırmayı production’a almadan önce nginx -t ile her zaman test edin ve değişiklikleri kademeli olarak hayata geçirin. Core Web Vitals metriklerinizi ve bant genişliği kullanımınızı izlemeye devam ederek optimizasyonun etkisini somut olarak ölçebilirsiniz.

Yorum yapın