Trafiği artan bir sitede en sık duyulan öneri şudur: Apache yetersiz kalıyor, Nginx'e geçin. Bu öneri çoğu zaman haklı ama gerekçesi sanıldığından farklı. Nginx'i hızlı kılan şey gizemli bir teknoloji değil, event-driven mimarisi ve doğru ayarlanmış birkaç direktiftir. Gerçek nginx performans optimizasyonu da bu direktiflerde saklı.
Nginx mimarisi neden bu kadar hızlı
Apache'nin klasik prefork modeli her bağlantı için ayrı bir process ya da thread açar. Bağlantı sayısı binlere çıktığında bu model belleği hızla tüketir, çünkü her process kendi başına bellek ayırır. Nginx ise event-driven, asenkron bir mimariyle çalışır: sabit sayıda worker process, binlerce bağlantıyı tek thread üzerinde event loop ile yönetir.
Bu farkın pratik sonucu nettir: aynı donanımda Nginx çok daha az bellekle çok daha fazla eşzamanlı bağlantı karşılar. Bu modelin ayar noktaları worker_processes ve worker_connections direktifleridir:
worker_processes auto;
events {
worker_connections 4096;
use epoll;
}
worker_processes auto değeri, sunucudaki CPU çekirdek sayısı kadar worker başlatır; çoğu kurulum için en iyi varsayılan budur.
worker_connections, her worker'ın açabileceği maksimum bağlantı sayısını belirler. Toplam kapasite worker_processes × worker_connections formülüyle hesaplanır.
Bu fark yük testinde açıkça ortaya çıkar. On bin eşzamanlı bağlantı altında Apache'nin prefork modeli gigabaytlarca bellek harcayabilirken, Nginx aynı yükü çok daha az bellekle taşır. CDN'lerin, reverse proxy katmanlarının ve yüksek trafikli sitelerin önünde bu yüzden neredeyse hep Nginx ya da benzer bir event-driven sunucu durur.
Nginx mi Apache mi: ne zaman hangisi
Bu soru genelde yanlış kurulur. İkisi birbirini dışlamaz; büyük altyapıların çoğunda ikisi bir arada çalışır. Nginx statik dosya sunumu, reverse proxy ve yüksek eşzamanlı bağlantı isteyen senaryolarda öne çıkar. Apache ise .htaccess ile dizin bazlı esnek yapılandırma gerektiren, mod_php gibi modül desteğine ihtiyaç duyan paylaşımlı hosting ortamlarında hâlâ tercih ediliyor.
| Kriter | Nginx | Apache |
|---|---|---|
| Eşzamanlı bağlantı performansı | Yüksek, düşük bellek kullanımı | Düşük, prefork'ta bellek maliyeti yüksek |
| Statik dosya sunumu | Doğal olarak hızlı | Ek modül ayarı gerektirebilir |
Dizin bazlı .htaccess desteği | Yok | Var |
| Reverse proxy / load balancer olarak kullanım | Çok yaygın | Mümkün ama daha az tercih edilir |
| Öğrenme eğrisi | Yapılandırma sözdizimi daha az esnek ama sade | Modül ekosistemi geniş, karmaşıklık artabilir |
Pratikte en yaygın kurulum katmanlıdır: önde Nginx reverse proxy ve statik dosya sunucusu olarak durur, arkada gerektiğinde Apache ya da doğrudan bir uygulama sunucusu (PHP-FPM, Node.js, Gunicorn) çalışır. Bu düzen, iki sunucunun güçlü yönlerini aynı anda kullanmayı mümkün kılar.
Server ve location blokları ile yapılandırma mantığı
Nginx yapılandırması server bloklarından ve bunların içindeki location bloklarından kurulur. Her server bloğu bir sanal host'u — bir domain ya da subdomain'i — temsil eder; location blokları ise belirli URL yollarına özgü kuralları tanımlar.

server {
listen 80;
server_name example.com www.example.com;
root /var/www/example/public;
index index.html index.php;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location /static/ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
Yapılandırmayı değiştirdikten sonra sunucuyu doğrudan yeniden başlatmayın. Önce sözdizimini test edin; sözdizimi sorunsuzsa reload komutuyla değişikliği kesintisiz uygulayın:
nginx -t
systemctl reload nginx
nginx -t hatası veren bir dosyayı fark etmeden reload etmek siteyi tamamen çökertebilir. Bu iki komutu ayrı adımlarda çalıştırmak, ihmal edilmemesi gereken bir alışkanlıktır.
Reverse proxy ve load balancing kurulumu
Nginx'in en yaygın kullanım alanlarından biri, arka planda çalışan uygulama sunucularının (Node.js, PHP-FPM, Gunicorn) önünde reverse proxy görevi görmesidir. Gelen isteği arka uca proxy_pass direktifi yönlendirir:
location /api/ {
proxy_pass http://127.0.0.1:3000;
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;
}
Arka uçta birden fazla sunucu çalışıyorsa yük dengeleme upstream bloğuyla kurulur. Nginx bunun için dört temel algoritma sunuyor: round-robin (varsayılan), least_conn, ip_hash ve ağırlıklı dağıtım.
upstream backend_pool {
least_conn;
server 10.0.0.11:3000 weight=3;
server 10.0.0.12:3000 weight=2;
server 10.0.0.13:3000 backup;
}
server {
location / {
proxy_pass http://backend_pool;
}
}
least_conn algoritması isteği en az aktif bağlantıya sahip sunucuya gönderir; oturum süresi değişken uygulamalarda round-robin'e göre daha dengeli sonuç verir. backup etiketi taşıyan sunucu, diğerleri çöktüğünde devreye girer. Açık kaynak Nginx'te sağlık kontrolü max_fails ve fail_timeout parametreleriyle sınırlıdır; gerçek anlamda aktif health check yalnızca Nginx Plus'ta bulunuyor.
| Algoritma | Dağıtım mantığı | En uygun senaryo |
|---|---|---|
| round-robin | Sırayla eşit dağıtır | Eşit kapasiteli sunucular |
| least_conn | En az bağlantılı sunucuya yönlendirir | Değişken oturum süresi |
| ip_hash | Aynı istemciyi hep aynı sunucuya gönderir | Oturum yapışkanlığı (sticky session) |
| ağırlıklı (weight) | Kapasiteye göre orantılı dağıtır | Farklı donanımlı sunucular |
Önbellekleme ile yanıt sürelerini kısaltma
Reverse proxy önbellekleme, arka uca giden istek sayısını azaltarak hem yanıt süresini hem de sunucu yükünü düşürür. Önbellek alanını proxy_cache_path tanımlar; bu önbelleğin hangi location'da kullanılacağını ise proxy_cache belirtir:

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m;
server {
location /api/ {
proxy_pass http://backend_pool;
proxy_cache api_cache;
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
add_header X-Cache-Status $upstream_cache_status;
}
}
X-Cache-Status başlığı bir yanıtın önbellekten mi (HIT) yoksa arka uçtan mı (MISS) geldiğini gösterir; önbellek performansını doğrulamanın en hızlı yolu budur. Statik dosyalarda tarayıcı önbelleğini expires direktifiyle ayarlamak, sunucu yükünü azaltan ayrı bir katmandır.
Açık kaynak Nginx'te önbellek geçersizleştirmek için doğrudan bir purge komutu yok. Bunun yerine iki yol izlenir: kısa proxy_cache_valid süreleri tanımlamak ya da içerik güncellendiğinde önbellek anahtarına bir versiyon parametresi eklemek.
Sıkıştırma ve statik dosya sunumunu hızlandırma
Gzip sıkıştırma, HTML, CSS, JS ve JSON gibi metin tabanlı içeriklerin boyutunu belirgin biçimde küçültür. Ayarı basittir; en sık yapılan hata, doğru MIME türlerini listeye eklememektir:

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
gzip_min_length 1024;
gzip_comp_level 5;
Statik dosyalarda sendfile, tcp_nopush ve tcp_nodelay direktifleri, dosyayı kernel alanından doğrudan ağ soketine kopyalatarak CPU yükünü düşürür:
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
keepalive_timeout, bir istemcinin aynı TCP bağlantısını ne kadar süre yeniden kullanabileceğini belirler. Değeri çok yüksek tutmak worker kapasitesini boşa harcar; çok düşük tutmak ise her istekte yeni bağlantı açma maliyetini geri getirir. 60-75 saniye aralığı çoğu site için makul bir denge kurar.
Brotli ile ek sıkıştırma katmanı
Gzip'in yanına, çoğu modern dağıtımda opsiyonel ngx_brotli modülü de eklenebilir. Brotli, özellikle metin tabanlı içeriklerde gzip'ten daha iyi bir sıkıştırma oranı verir. İkisini birlikte tanımlamak, Brotli destekleyen tarayıcılarda otomatik olarak Brotli'nin tercih edilmesini sağlar.
brotli on;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml;
brotli_comp_level 5;
Modül varsayılan Nginx paketinde bulunmaz; kaynağından derlenmesi ya da dağıtımın paket deposundan (libnginx-mod-http-brotli gibi) kurulması gerekir. brotli bloğu tanımlı olduğu hâlde modül kurulu değilse nginx -t hemen hata verir; bu yüzden kurulumdan sonra test etmek atlanmamalı.
Statik varlıklarda Cache-Control başlığını doğru ayarlamak, sıkıştırma kadar belirleyicidir. Sürüm numarası veya hash içeren dosya adlarında (app.a3f9c1.js gibi) uzun süreli önbellekleme, sürümsüz dosyalarda ise kısa süreli önbellekleme tercih edilir:
location ~* \.(js|css)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
location ~* \.(html)$ {
add_header Cache-Control "no-cache";
}
immutable direktifi, dosyanın süresi dolana kadar asla değişmeyeceğini tarayıcıya bildirir; tarayıcı bu sayede revalidation isteği bile göndermez. HTML dosyalarında no-cache kullanmak ise her istekte sunucuya sorulmasını, dolayısıyla güncel içeriğin garanti edilmesini sağlar.
Güvenlik yapılandırması ve rate limiting
SSL/TLS terminasyonu çoğunlukla Nginx katmanında yapılır. Let's Encrypt sertifikasıyla temel bir HTTPS bloğu şöyle kurulur:
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
}
http2 parametresi, tek bir TCP bağlantısı üzerinden birden çok isteğin paralel işlenmesini sağlayan HTTP/2 multiplexing'i devreye sokar. Bu, çok sayıda küçük dosya (CSS, JS, ikon) yükleyen sitelerde belirgin bir hız kazancı sağlar.
OCSP stapling ve HSTS ile TLS handshake'i hızlandırma
TLS handshake sırasında tarayıcı, sertifikanın iptal edilip edilmediğini OCSP sunucusuna sorar; bu sorgu ekstra bir gidiş-dönüş gecikmesi ekler. OCSP stapling bu doğrulamayı Nginx'in kendisine yaptırıp yanıta ekler; tarayıcının ayrıca sorgu atmasına gerek kalmaz.
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
HSTS (HTTP Strict Transport Security) başlığı, tarayıcıya belirli bir süre boyunca siteye yalnızca HTTPS üzerinden bağlanmasını bildirir; ilk isteğin bile HTTP'ye düşmesinin önüne geçer.
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
preload seçeneğini dikkatli kullanmak gerekir. Tarayıcıların önceden yüklenmiş HSTS listesine girmek, domaini uzun süreliğine tamamen HTTPS'e kilitler. Bu adımı geri almak zor olduğundan, önce preload olmadan test etmek, sorun çıkmazsa ardından eklemek daha güvenli bir sıradır.
Kaba kuvvet denemelerine ve aşırı istek saldırılarına karşı limit_req modülü devreye girer:
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/m;
location /login {
limit_req zone=login_limit burst=3 nodelay;
}
Bu kural, aynı IP adresinden /login yoluna dakikada 5'ten fazla istek gelmesini engeller. burst=3 ise kısa süreli ani yükleri belirli bir ölçüde tolere eder.
Rate limiting kurarken gözden kaçırılmaması gereken birkaç nokta var:
zoneboyutu (10m) yaklaşık 160 bin benzersiz IP adresini bellekte tutar.nodelaykullanılmazsa istekler kuyruğa alınır ve gecikme artar.- Proxy arkasında çalışan sitelerde gerçek istemci IP'si için
$binary_remote_addryerineX-Forwarded-Forbaşlığı kullanılmalı. - API endpoint'lerine ayrı
zonetanımlamak, login trafiğiyle genel trafiği birbirinden bağımsız sınırlara ayırır.
Güvenlik başlıklarını da aynı bloklara eklemek gerekir:
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Log analizi ile sorun tespiti
Nginx'in access ve error logları, performans sorunlarını teşhis etmede ilk bakılacak yerdir. Debian/Ubuntu tabanlı dağıtımlarda varsayılan konumları /var/log/nginx/access.log ve /var/log/nginx/error.log'dur.
# En cok istek gonderen IP adreslerini listeleme
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
# Son 50 hata satirini canli izleme
tail -f /var/log/nginx/error.log
Yanıt süresini loglara eklemek, hangi endpoint'in yavaşladığını görmeyi kolaylaştırır. Bunun için log_format direktifine $request_time ve $upstream_response_time değişkenlerini eklemek yeterlidir:
log_format timed '$remote_addr - $request_time $upstream_response_time '
'"$request" $status "$http_user_agent"';
access_log /var/log/nginx/access.log timed;
Log dosyaları büyüdükçe elle taramak pratik olmaktan çıkar; logrotate ile günlük rotasyon kurmak büyük siteler için işe yarar bir çözümdür. Hata loglarında sık tekrarlayan upstream timed out mesajları genelde arka uç uygulamanın yavaşladığına, connect() failed mesajları ise arka ucun tamamen çöktüğüne işaret eder.
goaccess ile anlık trafik panosu
goaccess, Nginx loglarını terminalde ya da tarayıcıda görsel bir panoya dönüştüren açık kaynak bir araçtır. Çoğu dağıtımda kurulumu tek komutla biter ve mevcut log formatını çoğunlukla otomatik tanır.
sudo apt install goaccess
goaccess /var/log/nginx/access.log --log-format=COMBINED -o /var/www/report.html --real-time-html
--real-time-html bayrağı, oluşan HTML raporunu WebSocket üzerinden canlı günceller; log dosyası büyüdükçe sayfa kendiliğinden yenilenir. Bu rapor en çok istek alan sayfaları, 404 üreten yolları, tarayıcı ve işletim sistemi dağılımını tek ekranda toplar.
Özel bir log_format kullanıyorsanız (yukarıdaki timed formatı gibi), goaccess bunu tanımayabilir; bu durumda --log-format parametresine kendi formatınızın karşılığını elle tanımlamak gerekir. goaccess çıktısını düzenli aralıklarla üretmek için bir cron görevi kurmak, raporu elle çalıştırmayı akıldan çıkarma riskini ortadan kaldırır.
Resmî Nginx dokümantasyonu tüm direktiflerin tam listesini ve varsayılan değerlerini içerir; yapılandırma yaparken buraya bakmak, forumlarda dolaşan eski ve zaman zaman hatalı örneklere güvenmekten daha sağlamdır (nginx.org/en/docs). Yapılandırmayı her değiştirdiğinizde nginx -t ile test etmek, üretim ortamında beklenmedik kesintilerin önüne geçen en basit alışkanlıktır.
Henüz yorum yok.
Sohbete katıl. Yorumlar yayınlanmadan önce moderasyondan geçer.