Nginx'te önbellek ve sıkıştırma
Bir web sayfasının hızını iki soru belirler: aynı içerik kaç kez yeniden üretiliyor ve ağ üzerinden kaç bayt taşınıyor? Önbellek (cache) ilk soruyu yanıtlar: bir kez hazırlanan içeriğin kopyası saklanır ve sonraki isteklerde yeniden üretilmeden sunulur. Sıkıştırma ikinci soruyu yanıtlar: yanıt gönderilmeden önce küçültülür, tarayıcı da onu açar.
Nginx bu iki işi birkaç yönerge (directive) ile yapar. Bu rehber önce her birinin ne işe yaradığını, sonra nasıl ayarlanacağını ve en önemlisi neyin önbelleğe alınmaması gerektiğini anlatır. Örnekler genel amaçlıdır; değerleri kendi sitenize göre seçin ve her değişiklikten sonra yapılandırmayı sınayın.
Kısaca
- Tarayıcı önbelleği tekrar gelen ziyaretçinin dosyaları yeniden indirmesini önler.
- gzip, metin tabanlı yanıtları küçültür; görsel ve arşivlere uygulanmaz.
- proxy_cache, arka uç sunucusunun yanıtını saklayıp sonraki isteklere doğrudan verir.
- Oturumlu ve kişiye özel sayfalar ortak önbelleğe alınmaz.
Dikkat
Yanlış kurulmuş bir sunucu önbelleği, bir kullanıcıya ait sayfayı başka bir kullanıcıya gösterebilir. Oturum açılan, sepet ya da kişisel bilgi içeren sayfaları önbelleğin dışında tuttuğunuzdan emin olmadan proxy_cache ya da fastcgi_cache açmayın.
Bu sayfada
Üç araç: tarayıcı önbelleği, sıkıştırma, sunucu önbelleği
-
Hangi önbellek nerede durur?
"Önbellek" tek bir şey değildir; istek yolunun farklı noktalarında üç ayrı kopya tutulabilir:
- Tarayıcı önbelleği: Ziyaretçinin kendi cihazındadır. Sunucu, yanıt başlıklarıyla "bu dosyayı şu kadar süre saklayabilirsin" der; tarayıcı o süre boyunca dosyayı yeniden istemez.
- Sunucu önbelleği (proxy_cache / fastcgi_cache): Nginx'in diskindedir. Nginx, ters vekil (reverse proxy) olarak arka uç sunucusundan (backend) aldığı yanıtı saklar ve aynı adrese gelen sonraki istekleri arka uca hiç gitmeden yanıtlar. Tüm ziyaretçiler için ortaktır.
- Ara önbellekler: CDN gibi hizmetler de aynı başlıklara bakarak kendi kopyalarını tutar. Ayrıntı için CDN rehberine bakın.
Sıkıştırma ise bir kopya tutmaz; yanıtı ağda taşınırken küçültür. Üçü birbirinin yerine geçmez, birlikte kullanılır.
: Büyüt -
Statik dosyalar için tarayıcı önbelleği
CSS, JavaScript, görsel ve yazı tipi dosyaları sık değişmez.
expiresyönergesi yanıtaExpiresveCache-Control: max-agebaşlıklarını ekler;add_header Cache-Controlile ek değerler (ör.public,immutable) verilir.Süreyi belirleyen şey, dosyanın adresinin değişip değişmediğidir:
- Sürümlü dosya adları (ör.
app.3f9a1c.css): içerik değişince ad da değiştiği için çok uzun süre (ör. bir yıl) veimmutableverilebilir.immutable, tarayıcıya "süre dolana kadar bu dosyayı yeniden doğrulamana gerek yok" der. - Adı sabit dosyalar (ör.
stil.css): uzun süre verirseniz güncellemeyi ziyaretçi geç görür. Daha kısa bir süre seçin ya da dosya adına sürüm ekleyin. - HTML sayfaları: genellikle
no-cacheverilir; tarayıcı kopyayı saklar ama her kullanımdan önce sunucuya sorar.
Nginx# Sürümlü dosyalar (ör. /assets/app.3f9a1c.css): içerik değişince ad da değişir location ^~ /assets/ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; } # Diğer statik dosyalar: adı sabit olduğu için daha kısa süre location ~* \.(?:css|js|jpg|jpeg|png|gif|webp|svg|ico|woff2)$ { expires 30d; add_header Cache-Control "public"; } # HTML sayfaları: kopya saklanır ama her kullanımdan önce sunucuya sorulur location / { add_header Cache-Control "no-cache"; try_files $uri $uri/ =404; }İki ayrıntıya dikkat edin. İlk blokta
^~vardır; olmasaydı/assets/app.cssisteği alttaki düzenli ifadelilocationile eşleşir ve kısa süre uygulanırdı. İkincisi,add_headeryönergeleri üst düzeyden yalnızca bulunulan düzeyde hiçadd_headeryoksa devralınır; birlocationiçine tek biradd_headeryazdığınızdaserverdüzeyinde tanımlı güvenlik başlıkları o konumda kaybolur ve yeniden yazılmaları gerekir. - Sürümlü dosya adları (ör.
-
gzip ile sıkıştırma
Tarayıcı isteğinde
Accept-Encoding: gzipbaşlığıyla sıkıştırılmış yanıt kabul ettiğini bildirir; Nginx yanıtı sıkıştırıpContent-Encoding: gzipile gönderir. HTML, CSS, JavaScript, JSON ve SVG gibi metin tabanlı içerik belirgin biçimde küçülür.Nginx# http bloğunun içinde: tüm siteler için geçerli olur gzip on; gzip_comp_level 5; gzip_min_length 1024; gzip_vary on; gzip_proxied any; # text/html her zaman sıkıştırılır; bu listeye yazılmaz gzip_types text/plain text/css text/xml application/json application/javascript application/xml application/rss+xml image/svg+xml;gzip on;sıkıştırmayı açar. Tek başına yalnızcatext/htmlyanıtlarını sıkıştırır.gzip_typesek içerik türlerini belirtir.text/htmlher zaman sıkıştırılır; listeye yazılmaz (yazılırsa Nginx yinelenen tür uyarısı verir).gzip_min_lengthbu bayt sayısından kısa yanıtları sıkıştırmaz (varsayılan 20). Çok küçük yanıtlarda kazanç olmadığı için daha yüksek bir eşik seçilir.gzip_comp_level1–9 arasıdır (varsayılan 1). Yüksek düzey daha çok işlemci harcar, kazanç ise giderek azalır; orta bir değer çoğu site için yeterlidir.gzip_vary on;yanıtaVary: Accept-Encodingekler; ara önbelleklerin sıkıştırılmış ve sıkıştırılmamış kopyaları karıştırmasını önler.gzip_proxied: Nginx, başka bir vekil sunucu (proxy) üzerinden gelen istekleri (istekteViabaşlığı olanları) varsayılan olarak sıkıştırmaz. Sitenizin önünde CDN ya da başka bir vekil varsa bu yönerge gerekir.
JPEG, PNG, WebP, video, ZIP ve PDF gibi biçimler zaten sıkıştırılmıştır; bunları listeye eklemek işlemciyi boşa harcar.
Brotli, gzip'e alternatif bir sıkıştırma yöntemidir. Nginx'in standart paketinde yer almaz; ayrı bir modülün kurulmasını gerektirir. Modül yokken
brotli on;yazmak yapılandırma hatasına yol açar. Brotli kullansanız bile gzip'i açık bırakın; onu desteklemeyen istemciler gzip alır.
: Büyüt -
proxy_cache ile sunucu önbelleği
Nginx arka uç sunucusunun önünde ters vekil olarak çalışıyorsa (bkz. reverse proxy kurulumu), yanıtları diskte saklayabilir. Aynı adrese gelen ilk istek arka uca gider ve yanıt saklanır (ıska, MISS); sonraki istekler süre dolana kadar doğrudan önbellekten yanıtlanır (isabet, HIT).
Nginx# Önbellek alanı: dizin, anahtar bölgesi (10 MB), disk sınırı, kullanılmayanı silme süresi proxy_cache_path /var/cache/nginx/site levels=1:2 keys_zone=site_onbellek:10m max_size=1g inactive=60m use_temp_path=off; # Oturum çerezi varsa 1, yoksa 0 (çerez adını uygulamanıza göre değiştirin) map $cookie_PHPSESSID $onbellek_atla { default 1; "" 0; } server { listen 80; server_name ornek.com; # Herkese aynı görünen sayfalar: önbellekli location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_cache site_onbellek; proxy_cache_key $scheme$host$request_uri; proxy_cache_valid 200 301 10m; proxy_cache_valid 404 1m; # Oturumu olan istek: önbellekten yanıtlama, yanıtı da saklama proxy_cache_bypass $onbellek_atla; proxy_no_cache $onbellek_atla; # Arka uç yanıt veremezse süresi dolmuş kopyayı sun proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; proxy_cache_lock on; add_header X-Cache-Status $upstream_cache_status; } # Yönetim paneli, sepet ve hesap sayfaları: önbellek yok location ~ ^/(yonetim|sepet|hesabim)(/|$) { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }proxy_cache_pathyalnızcahttpdüzeyinde yazılır: dosyaların duracağı dizin, anahtarların tutulduğu paylaşımlı bellek bölgesi (keys_zone=ad:boyut), disk üst sınırı (max_size) ve bu süre boyunca hiç istenmeyen kayıtların silinmesi (inactive).proxy_cachebölgeyi olocationiçin etkinleştirir.proxy_cache_keyiki isteğin "aynı" sayılmasını belirler. İçerik başka bir şeye göre de değişiyorsa (ör. dil çerezi) o değer anahtara eklenmelidir; yoksa bir dilde üretilen sayfa diğer dili isteyene verilir.proxy_cache_validdurum koduna göre saklama süresidir. Arka ucun gönderdiğiCache-Controlya daExpiresbaşlığı varsa o önceliklidir.proxy_cache_bypassisteğin önbellekten yanıtlanmamasını,proxy_no_cacheyanıtın önbelleğe yazılmamasını sağlar. Verilen değer boş ya da "0" değilse koşul geçerlidir. Örnektemap, oturum çerezi olan isteklerde değişkeni 1 yapar; çerez adını kendi uygulamanıza göre değiştirin.proxy_cache_use_stale, arka uç hata verdiğinde ya da yanıt vermediğinde süresi dolmuş kopyanın sunulmasına izin verir; kısa kesintilerde site açık kalır.add_header X-Cache-Status $upstream_cache_status;her yanıta önbellek durumunu yazar.
Nginx varsayılan olarak yalnızca GET ve HEAD isteklerini önbelleğe alır;
Set-Cookieiçeren ya daCache-Controlbaşlığındaprivate,no-cache,no-storebulunan yanıtları saklamaz. Bu davranışıproxy_ignore_headersile kapatmak, kişisel içeriğin sızmasının en sık nedenidir; ne yaptığınızdan emin değilseniz kullanmayın.
: Büyüt -
Neyi önbelleğe almamalı?
Sunucu önbelleği tüm ziyaretçiler için ortaktır. Kural basittir: yanıt, isteği yapan kişiye göre değişiyorsa ortak önbelleğe girmez.
- Oturum açılmış sayfalar: hesabım, siparişlerim, profil, kişiye özel fiyat ya da içerik.
- Sepet ve ödeme adımları.
- Yönetim paneli ve giriş sayfaları.
Set-Cookieiçeren yanıtlar: önbelleğe alınırsa bir kullanıcının oturum çerezi başkasına gönderilir.- Form gönderimleri (POST) ve tek kullanımlık belirteç (ör. CSRF) içeren sayfalar.
- API yanıtları: yetkilendirme başlığına göre değişenler.
En güvenli düzen, önbelleği yalnızca açıkça seçtiğiniz adreslerde (ana sayfa, ürün ve yazı sayfaları gibi herkese aynı görünen içerik) etkinleştirmek, panel ve hesap adreslerini ayrı bir
locationile önbelleksiz bırakmaktır. Oturum konusundaki genel önlemler için giriş ve oturum güvenliği rehberine bakın.
: Büyüt
Çalıştığını doğrulama: X-Cache-Status
Yapılandırmayı sınayıp yeniden yükledikten sonra yanıt başlıklarına bakın. Aynı adresi iki kez isteyin: ilk yanıtta MISS, ikincide HIT görmelisiniz.
# Yapılandırmayı sına, sorun yoksa yeniden yükle
sudo nginx -t && sudo systemctl reload nginx
# Statik dosya başlıkları: Cache-Control ve Expires görünmeli
curl -s -o /dev/null -D - https://ornek.com/assets/app.3f9a1c.css | grep -i -E "cache-control|expires"
# Sıkıştırma: Content-Encoding: gzip ve Vary: Accept-Encoding görünmeli
curl -s -o /dev/null -D - -H "Accept-Encoding: gzip" https://ornek.com/ | grep -i -E "content-encoding|vary"
# Sunucu önbelleği: aynı adresi iki kez isteyin (ilki MISS, ikincisi HIT)
curl -s -o /dev/null -D - https://ornek.com/ | grep -i x-cache-status
curl -s -o /dev/null -D - https://ornek.com/ | grep -i x-cache-status| Değer | Anlamı |
|---|---|
| MISS | Önbellekte kopya yoktu; yanıt arka uçtan alındı (ve uygunsa saklandı). |
| HIT | Yanıt doğrudan önbellekten verildi; arka uca gidilmedi. |
| BYPASS | proxy_cache_bypass koşulu sağlandı; önbellek atlandı. |
| EXPIRED | Kopyanın süresi dolmuştu; yanıt arka uçtan yeniden alındı. |
| STALE | Arka uç yanıt veremedi; süresi dolmuş kopya sunuldu. |
| UPDATING | Kopya yenilenirken eski kopya sunuldu. |
| REVALIDATED | Arka uç, süresi dolmuş kopyanın hâlâ geçerli olduğunu doğruladı. |
Sürekli MISS görüyorsanız arka ucun yanıtına bakın: Set-Cookie ya da Cache-Control: no-store gönderiyor olabilir. Örneğin PHP'de oturum başlatmak, varsayılan ayarlarla yanıta önbelleği engelleyen başlıklar ekler. Başlığı canlı sitede herkese göstermek istemiyorsanız sınama bittikten sonra kaldırabilirsiniz.
PHP-FPM kullanıyorsanız: fastcgi_cache
Nginx PHP'yi başka bir web sunucusuna değil doğrudan PHP-FPM'e iletiyorsa (fastcgi_pass), aynı mantık fastcgi_cache ailesiyle kurulur: fastcgi_cache_path, fastcgi_cache, fastcgi_cache_valid, fastcgi_cache_bypass, fastcgi_no_cache. Önemli bir fark, fastcgi_cache_key için varsayılan değer olmamasıdır; açıkça yazılmalıdır.
fastcgi_cache_path /var/cache/nginx/php levels=1:2 keys_zone=php_onbellek:10m
max_size=512m inactive=60m;
map $cookie_PHPSESSID $onbellek_atla {
default 1;
"" 0;
}
server {
listen 80;
server_name ornek.com;
root /var/www/ornek.com/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock; # soket yolu dağıtıma göre değişir
fastcgi_cache php_onbellek;
fastcgi_cache_key $scheme$request_method$host$request_uri; # varsayılanı yoktur
fastcgi_cache_valid 200 5m;
fastcgi_cache_bypass $onbellek_atla;
fastcgi_no_cache $onbellek_atla;
add_header X-Cache-Status $upstream_cache_status;
}
}PHP-FPM bağlantısının kendisi için Nginx ve PHP-FPM rehberine bakın.
Önbelleği temizleme
İçerik değişti ama önbellek eski kopyayı sunuyorsa birkaç yol vardır:
- Süreyi kısa tutmak: Sık değişen sayfalar için birkaç dakikalık
proxy_cache_validçoğu zaman yeterlidir; temizlemeye gerek kalmaz. - Dosyaları silmek: Önbellek dizinindeki dosyaları silmek tüm önbelleği boşaltır; Nginx sonraki isteklerde yanıtı arka uçtan yeniden alır. Yalnızca
proxy_cache_pathile tanımladığınız dizini hedefleyin. - Anahtarı değiştirmek:
proxy_cache_keyiçine bir sürüm değeri ekleyip değiştirmek, eski kayıtların tümünü bir anda geçersiz kılar; eski dosyalarinactivesüresi sonunda kendiliğinden silinir. - Tek adresi yenilemek:
proxy_cache_bypasskoşulunu yalnızca sizin gönderebileceğiniz bir işarete (ör. yalnızca kendi IP adresinizden kabul edilen bir istek başlığı) bağlarsanız, o istek arka uçtan taze yanıt alır ve kayıt yenilenir.
# Tüm sunucu önbelleğini boşalt.
# Yol, proxy_cache_path (ya da fastcgi_cache_path) ile tanımladığınız dizin olmalı; başka dizin yazmayın.
sudo find /var/cache/nginx/site -type f -deleteTek tek adresleri silen hazır bir "purge" özelliği, bildiğimiz kadarıyla Nginx'in açık kaynak sürümünde yerleşik değildir; ticari sürümde ya da üçüncü taraf modüllerle sağlanır. Kurulumunuzda hangisinin bulunduğunu kendi paketinizin belgelerinden doğrulayın.
Tarayıcı önbelleğini ise sunucudan temizleyemezsiniz; ziyaretçinin cihazındadır. Bu yüzden uzun süreli statik dosyalarda sürümlü dosya adı kullanmak tek güvenilir yoldur.
Sık yapılan hatalar
- Adı değişmeyen CSS ve JavaScript dosyalarına bir yıllık süre vermek; güncelleme ziyaretçilere ulaşmaz.
gzip_typeslistesinetext/htmlya da görsel türleri eklemek.- Oturum çerezini denetlemeden tüm siteye
proxy_cacheaçmak. proxy_ignore_headers Set-Cookie Cache-Control;satırını ne yaptığını bilmeden kopyalamak.- Dile, cihaza ya da para birimine göre değişen içerikte bu değeri önbellek anahtarına eklememek.
- Bir
locationiçineadd_headeryazıp üst düzeydeki güvenlik başlıklarının kaybolduğunu fark etmemek (bkz. güvenlik başlıkları). - Önbellek dizinini Nginx'in çalıştığı kullanıcının yazamayacağı bir yere koymak.
Kontrol listesi
- Statik dosyalar
expiresile süre alıyor; uzun süre yalnızca sürümlü dosya adlarında. - gzip açık;
gzip_typesyalnızca metin tabanlı türleri içeriyor,gzip_vary on. - Sunucu önbelleği yalnızca herkese aynı görünen adreslerde etkin.
- Oturum çerezi olan istekler
proxy_cache_bypassveproxy_no_cacheile hariç. - Yönetim paneli, sepet ve hesap sayfaları önbelleksiz.
X-Cache-Statusile MISS ve HIT gözlendi; oturum açıkken BYPASS görülüyor.- Önbelleği nasıl temizleyeceğiniz yazılı ve denenmiş.
- Her değişiklikten sonra
nginx -tçalıştırıldı.
Sık sorulan sorular
Önbellek açınca sitedeki değişiklikler neden hemen görünmüyor?
Çünkü tarayıcı ya da sunucu, süresi dolmamış eski kopyayı sunuyor. Sunucu önbelleğini temizleyebilir ya da süresini kısaltabilirsiniz; tarayıcı önbelleği için kalıcı çözüm, statik dosyalarda sürümlü dosya adı kullanmaktır.
gzip mi, Brotli mi kullanmalıyım?
gzip Nginx ile birlikte gelir ve her tarayıcıda çalışır; önce onu açın. Brotli ayrı bir modül gerektirir. Modülü kurabiliyorsanız ikisini birlikte kullanabilirsiniz; tarayıcı desteklediğini seçer.
Sürekli MISS görüyorum, neden?
En sık nedenler: arka ucun Set-Cookie ya da Cache-Control: no-store, private göndermesi, isteğin oturum çerezi taşıması, proxy_cache_valid tanımlanmamış olması ya da adresin her istekte değişen bir sorgu parametresi içermesi.
proxy_cache ile fastcgi_cache arasındaki fark nedir?
Mantık aynıdır; fark Nginx'in yanıtı nereden aldığıdır. Arka uç HTTP ile konuşan bir sunucuysa (proxy_pass) proxy_cache, doğrudan PHP-FPM ise (fastcgi_pass) fastcgi_cache kullanılır.
CDN kullanıyorsam Nginx önbelleğine gerek var mı?
İkisi birbirini tamamlar. CDN içeriği ziyaretçiye yakın noktalardan sunar; Nginx önbelleği ise CDN'in sunucunuza ilettiği isteklerde uygulamanın yükünü azaltır. Önbellek başlıklarınız doğruysa ikisi de aynı kurallara uyar.
BYK Yazılım Destek Ekibi
Bu rehber BYK Yazılım destek ekibi tarafından hazırlanır ve düzenli olarak gözden geçirilir. Son güncelleme: 04.10.2026.
İlgili rehberler
- Nginx ile reverse proxy (ters vekil) kurulumuserver bloğu, proxy_pass, iletilecek başlıklar, WebSocket, zaman aşımları ve gerçek IP ayarıyla adım adım kurulum.
- Nginx ve PHP-FPM: PHP siteleri Nginx ile nasıl çalışır?fastcgi_pass, SCRIPT_FILENAME, try_files, havuz (pool) kavramı, soket izinleri ve 502 hatası.
- CDN (içerik dağıtım ağı) nedir?CDN'in ne olduğu, nasıl devreye alındığı ve gerçek IP, önbellek, kaynak sunucu güvenliği konusunda dikkat edilecekler.
- 502, 504 ve diğer Nginx hataları: nedenleri ve çözümleri502, 504, 413, 499, 403 ve 404 hatalarının anlamı, olası nedenleri, günlüklerle teşhisi ve çözümü.
Web sitenizin altyapısını birlikte konuşalım
BYK Yazılım kurumsal web siteleri geliştirir. Sitenizle ilgili sorularınız için bize yazabilirsiniz.
Bize ulaşın Kurumsal web sitesi hizmetimiz