Nginx ile Gzip Sıkıştırma Sorunları ve Çözümleri
Web sunucunuzda sayfalar yavaş yükleniyorsa ve network trafiğiniz beklenenden fazlaysa, büyük ihtimalle gzip sıkıştırma ya hiç çalışmıyor ya da yanlış yapılandırılmış demektir. Nginx’te gzip konfigürasyonu ilk bakışta basit gibi görünse de pratikte onlarca farklı sorunla karşılaşabilirsiniz. Yıllarca üretim ortamlarında nginx yönetirken “gzip neden çalışmıyor?” sorusuyla defalarca boğuştum. Bu yazıda en sık karşılaşılan gzip sorunlarını, debug yöntemlerini ve çözüm yollarını gerçek senaryolarla ele alacağım.
Gzip Neden Önemli ve Nerede Yanlış Gider?
Gzip sıkıştırma, HTTP yanıtlarını istemciye göndermeden önce sıkıştırarak bant genişliği kullanımını dramatik biçimde azaltır. HTML, CSS, JavaScript gibi text tabanlı dosyalar %60-80 oranında küçülebilir. Ancak nginx’te bu özelliği etkinleştirmek “tek satır ekleyip geç” meselesi değil.
Sorunlar genellikle şu kategorilerde yaşanır:
- Konfigürasyon hataları: Yanlış direktifler, eksik MIME type tanımlamaları
- Proxy ve CDN çatışmaları: Upstream sunucularla gzip header çakışmaları
- Statik dosya cache sorunları: Önceden sıkıştırılmış dosyaların tekrar sıkıştırılması
- Buffer ve boyut sınırları: Küçük dosyaların sıkıştırılmaması
- SSL/TLS ile etkileşim: BREACH gibi güvenlik açıkları nedeniyle gzip devre dışı bırakma
Temel Konfigürasyon ve Doğrulama
Önce standart bir gzip konfigürasyonuna bakalım:
# /etc/nginx/nginx.conf veya site konfigürasyonu
http {
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/javascript
application/x-javascript
application/xml
application/xml+rss
application/json
application/ld+json
application/manifest+json
font/ttf
font/woff
font/woff2
image/svg+xml
image/x-icon;
}
Konfigürasyonu yaptıktan sonra ilk doğrulama adımı nginx syntax kontrolü:
# Syntax kontrolü
nginx -t
# Konfigürasyonu reload et
systemctl reload nginx
# Gzip çalışıyor mu? curl ile test
curl -H "Accept-Encoding: gzip" -I https://example.com/style.css
# Daha detaylı test
curl -v -H "Accept-Encoding: gzip,deflate" https://example.com/ 2>&1 | grep -i "content-encoding"
Yanıtta Content-Encoding: gzip görüyorsanız temel konfigürasyon çalışıyor demektir. Görmüyorsanız debug sürecine girelim.
Sorun 1: Content-Encoding Header Gelmiyor
Bu en yaygın şikayet. Konfigürasyonu eklediniz, nginx’i reload ettiniz ama hala gzip header yok.
Adım 1: nginx.conf lokasyonunu kontrol edin
Bazen gzip direktiflerini yanlış bloğa yazıyoruz. Gzip sadece http bloğunda değil, server ve location bloklarında da tanımlanabilir. Ancak dikkat edilmesi gereken nokta, location bloğundaki tanımlama o lokasyon için geçerli olurken üst bloğu ezebilir.
# Aktif konfigürasyonu kontrol et
nginx -T | grep -A 20 "gzip"
# Include edilen dosyaları da görmek için
nginx -T 2>/dev/null | grep gzip
Adım 2: MIME type listesini kontrol edin
Sıkıştırma çalışmıyorsa dosya türü gzip_types listesinde olmayabilir. application/json API yanıtlarında sık yaşanan bir sorun:
# Dosyanın content-type'ını öğren
curl -I https://example.com/api/data | grep -i content-type
# O content-type için gzip çalışıyor mu?
curl -H "Accept-Encoding: gzip" -I https://example.com/api/data | grep -i content-encoding
Adım 3: gzip_min_length kontrolü
Çok küçük dosyalar sıkıştırılmaz. Varsayılan gzip_min_length 20 bayt iken bunu 256 veya 1024 olarak ayarladıysanız küçük dosyalar sıkıştırılmaz:
# Dosya boyutunu kontrol et
curl -s https://example.com/style.css | wc -c
# Eğer boyut gzip_min_length'ten küçükse sıkıştırılmaz
# Test için min_length'i 0 yap ve dene
Sorun 2: Proxy Arkasındaki Nginx’te Gzip Sorunları
Gerçek hayatta nginx çoğunlukla bir proxy olarak çalışır: upstream’de uygulama sunucusu (Node.js, PHP-FPM, Gunicorn vb.) vardır. Bu yapıda gzip sorunları karmaşıklaşır.
Şöyle bir senaryo düşünün: upstream uygulamanız zaten gzip sıkıştırılmış yanıt dönüyor, nginx de tekrar sıkıştırmaya çalışıyor. Sonuç bozuk yanıtlar veya double encoding.
# Upstream'in zaten gzip döndürüp döndürmediğini kontrol et
# (doğrudan upstream'e bağlanarak)
curl -H "Accept-Encoding: gzip" -I http://127.0.0.1:8080/api/test
# nginx access log'unda upstream başlıklarını görüntülemek için
# log formatını genişlet
Bu durumda nginx konfigürasyonunda dikkatli olunmalı:
# /etc/nginx/sites-available/myapp.conf
upstream myapp {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name example.com;
# Upstream zaten sıkıştırıyorsa gunzip ile aç, nginx tekrar sıkıştırsın
gunzip on;
# Ya da proxy_pass ile upstream compression'ı yönet
location / {
proxy_pass http://myapp;
# Upstream'e gzip isteği gönderme
proxy_set_header Accept-Encoding "";
# nginx tarafında sıkıştır
gzip on;
gzip_types text/plain application/json text/css application/javascript;
}
}
gzip_proxied direktifi de kritik:
- gzip_proxied off: Proxy yanıtlarını sıkıştırma (varsayılan)
- gzip_proxied any: Tüm proxy yanıtlarını sıkıştır
- gzip_proxied expired: Sadece Cache-Control: no-cache olmayan yanıtları sıkıştır
- gzip_proxied no-cache: Cache-Control: no-cache başlıklı yanıtları sıkıştır
- gzip_proxied no-store: Cache-Control: no-store başlıklı yanıtları sıkıştır
- gzip_proxied auth: Authorization başlığı olan yanıtları sıkıştır
Sorun 3: CDN ve Load Balancer Katmanında Sorunlar
Cloudflare, AWS CloudFront veya benzeri bir CDN kullanıyorsanız, CDN kendi gzip/brotli sıkıştırmasını yapabilir. Bu durumda nginx’ten CDN’e gelen yanıtın sıkıştırılmış olup olmadığı ve CDN’in bunu nasıl ilettiği önemli.
Bir üretim ortamında karşılaştığım senaryo: CDN’den gelen Accept-Encoding: identity başlığı nedeniyle nginx gzip uygulamıyordu.
# CDN'nin nginx'e ne gönderdiğini görmek için geçici debug log ekle
# nginx.conf veya server bloğuna:
log_format debug_gzip '$remote_addr - $request '
'upstream_http_content_encoding: $upstream_http_content_encoding '
'sent_http_content_encoding: $sent_http_content_encoding '
'http_accept_encoding: $http_accept_encoding';
access_log /var/log/nginx/gzip_debug.log debug_gzip;
# Log'u izle
tail -f /var/log/nginx/gzip_debug.log
# Test isteği gönder
curl -H "Accept-Encoding: gzip" https://example.com/test
# Log'da http_accept_encoding alanı boşsa sorun burada
Sorun 4: Statik Dosyalar İçin gzip_static
Eğer build sürecinizde önceden .gz dosyaları oluşturuyorsanız (webpack, gulp vb.), nginx’in bu pre-compressed dosyaları kullanmasını sağlayabilirsiniz. Ancak bu yapıda da sorunlar çıkabilir.
# webpack veya build aracıyla önceden sıkıştırılmış dosya oluşturma
gzip -k -9 /var/www/html/assets/bundle.js
ls -la /var/www/html/assets/
# bundle.js ve bundle.js.gz ikisi de olmalı
# nginx.conf gzip_static konfigürasyonu
server {
listen 80;
server_name example.com;
root /var/www/html;
# Önceden sıkıştırılmış dosyaları kullan
gzip_static on;
location /assets/ {
gzip_static on;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
gzip_static modülünün kurulu olup olmadığını kontrol edin:
nginx -V 2>&1 | grep -o "with-http_gzip_static_module"
# Çıktı "with-http_gzip_static_module" ise modül mevcut
# Eğer yoksa Ubuntu/Debian'da
apt-get install nginx-extras
# CentOS/RHEL'de
yum install nginx-mod-http-gzip-static
Sorun 5: Bozuk veya Tutarsız Gzip Yanıtları
Bazen gzip etkin ama tarayıcı sayfayı düzgün render etmiyor, ya da “Content Encoding Error” alıyorsunuz. Bu genellikle şu nedenlerden olur:
Double compression (çift sıkıştırma): Uygulama zaten gzip sıkıştırıyorsa ve nginx de sıkıştırıyorsa yanıt bozulur.
# Gerçek content-encoding durumunu gör
curl -v -H "Accept-Encoding: gzip" https://example.com/ 2>&1 | grep -E "(Content-Encoding|content-encoding)"
# Yanıtı decode et ve içeriği kontrol et
curl -H "Accept-Encoding: gzip" https://example.com/ | gunzip - | head -20
# Eğer gunzip hata veriyorsa double compression olabilir
# Ya da:
curl -H "Accept-Encoding: gzip" https://example.com/ > /tmp/response.gz
file /tmp/response.gz
# "gzip compressed data" çıkmalı, başka bir şey çıkıyorsa sorun var
Buffer sorunları: Büyük dosyalarda buffer boyutu yetersiz kalabilir:
# nginx.conf
http {
gzip on;
gzip_buffers 32 4k; # ya da 16 8k - duruma göre ayarla
# Proxy buffer ayarları da önemli
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
Sorun 6: Vary Header Eksikliği ve Cache Sorunları
Vary: Accept-Encoding başlığı olmadan CDN veya tarayıcı cache’i yanlış çalışabilir. Örneğin gzip desteklemeyen bir istemci, cache’deki sıkıştırılmış yanıtı alırsa sayfa bozuk görünür.
# Vary header kontrolü
curl -I -H "Accept-Encoding: gzip" https://example.com/ | grep -i vary
# Beklenen çıktı:
# Vary: Accept-Encoding
# Konfigürasyonda gzip_vary on olduğundan emin ol
# nginx.conf:
gzip_vary on;
# Bu direktif otomatik olarak Vary: Accept-Encoding ekler
# Eğer proxy kullanıyorsanız proxy_set_header Vary ile de yönetebilirsiniz
# Bazı CDN'ler Vary başlığını kaldırıyor, kontrol için:
curl -sI https://example.com | grep -i vary
curl -sI https://origin.example.com | grep -i vary
# İkisi aynı değilse CDN müdahale ediyor demektir
Log Analizi ile Gzip Sorunlarını Takip Etme
Üretim ortamında gzip sorunlarını izlemek için özel log formatı kullanmak hayat kurtarır:
# /etc/nginx/nginx.conf - genişletilmiş log format
http {
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time '
'ce="$sent_http_content_encoding" '
'ae="$http_accept_encoding" '
'ct="$sent_http_content_type" '
'bs=$bytes_sent '
'bl=$body_bytes_sent';
access_log /var/log/nginx/access.log compression;
}
Bu log formatıyla hangi dosyaların sıkıştırıldığını, hangilerinin sıkıştırılmadığını ve bant genişliği tasarrufunu analiz edebilirsiniz:
# Gzip ile gönderilen istekleri filtrele
grep 'ce="gzip"' /var/log/nginx/access.log | wc -l
# Gzip olmadan gönderilen büyük yanıtları bul (potansiyel sorunlar)
awk '$NF ~ /ce=""/ && $8 > 10000' /var/log/nginx/access.log
# Toplam bytes_sent vs body_bytes_sent farkı (sıkıştırma oranı tahmini)
awk '{sum_bytes += $12; sum_body += $13} END {print "Total bytes:", sum_bytes, "Body bytes:", sum_body, "Ratio:", sum_body/sum_bytes}' /var/log/nginx/access.log
Güvenlik Notları: BREACH Saldırısı ve Gzip
BREACH (Browser Reconnaissance and Exfiltration via Adaptive Compression of Hypertext) saldırısı, SSL/TLS üzerinden gzip sıkıştırma kullanan sitelere karşı çalışır. Özellikle sayfada kullanıcı girdisi yansıtılıyorsa ve CSRF token gibi gizli değerler varsa risk artar.
Bu nedenle bazı güvenlik odaklı konfigürasyonlarda gzip’i seçici kullanmak gerekir:
# Sadece statik asset'lerde gzip, HTML sayfalarında kapalı
server {
gzip off; # Global kapalı
location ~* .(css|js|svg|woff|woff2)$ {
gzip on;
gzip_types text/css application/javascript image/svg+xml font/woff font/woff2;
expires 1y;
}
location / {
# HTML içerik için gzip kapalı (BREACH önlemi)
gzip off;
proxy_pass http://app_backend;
}
}
Performans Testi ve Doğrulama
Gzip düzgün çalışıyor mu, gerçekten tasarruf sağlıyor mu? Bunu ölçmek için:
# Sıkıştırılmış ve sıkıştırılmamış boyutları karşılaştır
echo "=== Gzip olmadan ==="
curl -s -o /dev/null -w "%{size_download} bytes" https://example.com/
echo ""
echo "=== Gzip ile ==="
curl -s -H "Accept-Encoding: gzip" -o /dev/null -w "%{size_download} bytes" https://example.com/
# Daha kapsamlı test - birden fazla kaynak için
for url in "/" "/style.css" "/app.js" "/api/data"; do
size_plain=$(curl -s -o /dev/null -w "%{size_download}" https://example.com${url})
size_gzip=$(curl -s -H "Accept-Encoding: gzip" -o /dev/null -w "%{size_download}" https://example.com${url})
echo "URL: ${url} | Plain: ${size_plain} | Gzip: ${size_gzip} | Tasarruf: $(( (size_plain - size_gzip) * 100 / size_plain ))%"
done
# Apache Bench ile gzip performans testi
ab -n 1000 -c 50 -H "Accept-Encoding: gzip" https://example.com/
# siege ile test
siege -c 25 -t 60S -H "Accept-Encoding: gzip" https://example.com/
Hızlı Kontrol Listesi
Gzip sorun yaşadığınızda sırayla şunları kontrol edin:
- nginx -t çıktısı temiz mi?
- Gzip direktifleri doğru blokta mı (http, server veya location)?
gzip_typeslistesinde soruna neden olan MIME type var mı?- Dosya boyutu
gzip_min_lengthdeğerinden büyük mü? gzip_proxieddeğeri proxy setup’ınıza uygun mu?- Upstream uygulama zaten gzip gönderiyor mu (double compression)?
gzip_vary onayarlı mı?- CDN veya load balancer
Accept-Encodingbaşlığını değiştiriyor mu? gzip_staticiçin.gzdosyaları mevcut ve güncel mi?- nginx’in doğru modüllerle derlenmiş mi (
nginx -V)?
Sonuç
Nginx’te gzip sıkıştırma sorunları genellikle basit konfigürasyon hatalarından ya da katmanlı mimari (proxy, CDN, load balancer) etkileşimlerinden kaynaklanır. Sorun yaşadığınızda panik yapmadan önce curl -v ile header analizi yapın, log formatını genişleterek veriyi toplayın ve katman katman debug edin.
Üretim ortamında gzip’i etkinleştirirken BREACH güvenlik açığını göz önünde bulundurun, özellikle dinamik HTML içerik sunan uygulamalarda seçici davranın. Statik asset’ler için gzip_static ile pre-compressed dosyalar kullanmak hem CPU yükünü azaltır hem de yanıt sürelerini iyileştirir.
En önemlisi, değişiklik yaptıktan sonra her zaman ölçün. Gzip ne kadar tasarruf sağladığını, hangi içerik türlerinde etkili olduğunu ve gerçek kullanıcı deneyimine katkısını log analizi ve performans testleriyle doğrulayın. Sayısal veri olmadan yapılan optimizasyon, tahmin oyunundan öteye geçmez.
