İçeriğe geç

Teknik derinlik

nginx DDoS Sıkılaştırma: Bağlantı Limitleri, Oran Bölgeleri ve Timeout'lar

Son güncelleme: Ağustos 2026 · Oran bölgeleri, bağlantı limitleri ve timeout'lar · Okuma süresi ~19 dk

Ortada sakin bir işçi halkası düzenli biçimde jeton alıp verirken, etraflarındaki ölçümlü bir kapıda büyük amber bir kalabalık bekliyor; işçilere yalnızca kontrollü bir sızıntı ulaşıyor.

nginx yavaş bağlantı saldırılarına tasarım gereği dayanıklıdır, çünkü bir olay döngüsü bağlantı başına iş parçacığı harcamaz. Ama istek seline karşı yapılandırılana kadar hiçbir şey yapmaz. Taşıyıcı direktifler limit_req_zone, limit_conn_zone ve dört timeout'tur; $binary_remote_addr üzerine anahtarlanır, kendi temel ölçülerinize göre boyutlanır ve tek bir gerçek kullanıcıyı düşürmeden önce limit_req_dry_run ile sınanır.

Bu rehber, önünde herhangi bir cihaz olmadan nginx’in kendisini bir DDoS saldırısının istek ve bağlantı tüketen kısmına karşı sıkılaştırır. nginx bir mimari avantajla başlar: olay döngüsü onu, iş parçacığı başına bağlantı açan bir sunucuya kıyasla yavaş bağlantı saldırılarına çok daha dayanıklı kılar. Ama bu avantaj tam olarak tek bir saldırı biçimini kapsar. İstek seline karşı, kutudan çıkan bir nginx siz ona limit verene kadar hiçbir şey yapmaz.

Aşağıdaki her direktif değeri, çalıştığını gösteren sayacı ve yeri geldiğinde dry-run’ıyla birlikte verilir. Değerler kendi trafiğinize göre ölçülen başlangıç noktalarıdır. Bir rehberden kopyalanan oran ya işe yaramaz ya da kendi kullanıcılarınızı kısar.

Saldırı biçimleri ve bunları karşılayan nginx direktifleri
CihazSaldırı biçiminginx direktifiDoğrulama
Az kaynaktan istek selilimit_req_zone + limit_req (burst, nodelay)access log'da 429 oranı; önce limit_req_dry_run
Kaynak başına çok eşzamanlı bağlantılimit_conn_zone + limit_connlimit_conn_status 429; stub_status'ta $connections
Yavaş başlık / yavaş gövde (Slowloris)client_header_timeout, client_body_timeoutreset_timedout_connection; error log info düzeyinde
Büyük başlık / büyük gövde istismarılarge_client_header_buffers, client_max_body_sizeaccess log'da 413 / 400 oranı
Tanıtıcı / worker tükenmesiworker_connections, worker_rlimit_nofilestub_status active değeri, worker_connections tavanına karşı

Her satır nginx.conf içinde ayarlanır ve access log ya da stub_status'tan doğrulanır. Saldırı nginx'in önündeki hattı doldurduğunda bunların hiçbiri işe yaramaz, çünkü o bir şebeke katmanı sorunudur.

0. Önce temel ölçüler: ayarlayacağınız sayıları açın

Ölçmediğiniz bir oran limitini boyutlandıramazsınız. stub_status’ı etkinleştirin ve access log’un istek süresini ve limit durumunu taşıdığından emin olun:

# In an internal-only server block
location = /nginx_status {
    stub_status;
    allow 127.0.0.1;
    deny all;
}

# A log format that shows rate/conn limiting and timing
log_format ddos '$remote_addr $status $request_time '
                '$limit_req_status $limit_conn_status "$request"';
access_log /var/log/nginx/access.log ddos;
# Live connection state
curl -s http://127.0.0.1/nginx_status
# Active connections, reading/writing/waiting; compare 'Active' to worker_connections

# Requests per second per client, from the log, over a normal week
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head

Active sayısının worker_connections tavanına oranı ve log’daki istemci başına istek hızı, aşağıdaki her eşiğin kendisine göre seçildiği iki temel ölçüdür.

1. Worker kapasitesi: her şeyin altında duran tavan

Herhangi bir oran kuralından önce nginx’e yeterli bağlantı ve tanıtıcı izni verilmelidir, yoksa bir limit hiç ateşlenmeden kendini tüketir.

worker_processes auto;              # one per core
worker_rlimit_nofile 262144;        # must be >= worker_connections * 2

events {
    worker_connections 32768;       # per worker; total = this * worker_processes
    multi_accept on;
    use epoll;                      # Linux; the event loop that makes nginx scale
}

worker_rlimit_nofile, worker_connections’ı üst sağlayıcı soketlerine ve dosyalara yer bırakacak kadar aşmalıdır. İşletim sistemi servis limiti de sırasıyla bunu aşmalıdır; systemd biriminde bir LimitNOFILE, Linux sıkılaştırma rehberinde ele alındığı gibi. İşletim sistemi limiti daha düşükse, hiçbir nginx direktifinin yükseltemeyeceği gerçek tavan odur.

# Confirm nginx actually got the descriptors
cat /proc/$(pgrep -o -x nginx)/limits | grep 'open files'

2. Oran sınırlama: limit_req, birincil istek seli savunması

limit_req_zone istemci adresi üzerine anahtarlanan paylaşımlı bir bellek bölgesi tanımlar, limit_req onu uygular. Bu, nginx’teki en önemli DDoS direktifidir.

# http context — one zone, keyed on the binary client address
limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=2r/s;

server {
    location / {
        limit_req zone=perip burst=20 nodelay;
        limit_req_status 429;
    }
    # A stricter zone on the expensive path
    location = /login {
        limit_req zone=login burst=5 nodelay;
        limit_req_status 429;
    }
}

rate sürdürülebilir tavandır, burst kısa sıçrama payıdır, nodelay sıçramayı araya boşluk koymak yerine hemen sunar. 10 MB’lık bir bölge yaklaşık 160.000 IPv4 girdisi tutar, çünkü $binary_remote_addr adresi dört baytta saklar.

Önce dry-run ile devreye alın. Sıkılaştırma ile kesinti arasındaki fark budur:

# Log what WOULD be limited, but let everything through
limit_req_dry_run on;
# Read what the dry-run would have rejected, per client
grep 'limiting requests' /var/log/nginx/error.log | awk '{print $NF}' | sort | uniq -c | sort -rn

limit_req_dry_run on’ı temsili bir hafta açık bırakın, sınırlayacağı istemcilerin gerçek trafiğiniz olmadığını doğrulayın, sonra kapatın ki kural devreye girsin.

3. Bağlantı sınırlama: eşzamanlılığa karşı limit_conn

limit_req istek hızını sınırlarken, limit_conn kaynak başına eşzamanlı bağlantı sayısını sınırlar. Bu, çok sayıda bağlantı açıp tutan bir istemciye karşı savunmadır.

limit_conn_zone $binary_remote_addr zone=connperip:10m;

server {
    location / {
        limit_conn connperip 20;    # max 20 concurrent connections per source
        limit_conn_status 429;
    }
}
# Rejections show in the access log as the status you set
awk '$2==429' /var/log/nginx/access.log | wc -l

4. Timeout’lar: Slowloris’e yakın bağışıklığı gerçek bağışıklığa çevirmek

nginx bağlantı başına iş parçacığı harcamaz, bu yüzden yavaş bir bağlantı ucuzdur. Ama bedava değildir, çünkü tanıtıcı sonludur. Timeout’lar asılı kalan bağlantıları birikmeden önce tahliye eder:

client_header_timeout 5s;      # time allowed to send the full request header
client_body_timeout 5s;        # time allowed between body reads
send_timeout 10s;              # time allowed between successful writes to the client
keepalive_timeout 30s;         # idle keep-alive lifetime
keepalive_requests 100;        # requests per keep-alive connection
reset_timedout_connection on;  # send RST on timeout, freeing the socket immediately

Kısa başlık ve gövde timeout’ları doğrudan Slowloris cevabıdır. Başlıklarını damla damla gönderen bir bağlantı, bir tanıtıcıyı dakikalarca tutmadan önce 5 saniyede düşürülür.

# Timed-out connections appear in the error log at 'info'
grep -Ei 'timed out|timeout' /var/log/nginx/error.log | tail

5. Tampon ve boyut limitleri: büyük istek yüzeyini kapatmak

Bir saldırgan aşırı büyük başlık veya gövdelerle belleği de tüketebilir. Bunları sınırlayın:

client_max_body_size 10m;              # reject bodies larger than this (413)
large_client_header_buffers 4 8k;      # count and size of large header buffers
client_header_buffer_size 1k;
# 413 (body too large) and 400 (bad/oversized header) rates
awk '$2==413 || $2==400' /var/log/nginx/access.log | wc -l

6. Proxy arkasında istemci IP’sini doğru almak

Her oran ve bağlantı bölgesi istemci adresi üzerine anahtarlanır. Bir yük dengeleyici ya da CDN arkasında bu adres, siz düzeltmedikçe proxy’nin adresidir. O durumda her gerçek istemci tek bir kovayı paylaşır ve limitler anlamsızlaşır.

# Trust the proxy ranges and read the real client from its header
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
# Confirm the log now shows real client IPs, not the proxy's single address
awk '{print $1}' /var/log/nginx/access.log | sort -u | wc -l

Bu sayı 1 ise, her istek proxy’ye atfediliyordur ve limitleriniz yanlış anahtarlanmıştır. Bu, özenle yazılmış bir oran limitinin ya herkesi kısmasının ya da hiç kimseyi kısmamasının en yaygın sebebidir.

7. Limit altında ucuz bir yanıt sunmak

Bir limit ateşlendiğinde, kendisi iş maliyeti olan bir hata sayfası yerine ucuz bir şey sunun:

limit_req_status 429;
limit_conn_status 429;
error_page 429 = @ratelimited;
location @ratelimited {
    default_type text/plain;
    return 429 "Too Many Requests\n";
}

Statik bir 429 sunmak neredeyse hiçbir şeye mal olmaz, böylece limit kendi küçük yükseltmesine dönüşmez.

İzlemeye bağlanacak sinyaller

# 1. 429 rate — the limits firing
awk '$2==429' /var/log/nginx/access.log | wc -l
# 2. Active vs ceiling — worker saturation
curl -s http://127.0.0.1/nginx_status | awk '/Active/{print $3}'
# 3. Timed-out (Slowloris) connections
grep -c 'timed out' /var/log/nginx/error.log
# 4. Descriptor headroom
cat /proc/$(pgrep -o -x nginx)/limits | grep 'open files'

Yükselen bir 429 oranı, limitlerin çalıştığını gösterir. Active değerinin worker_connections’a yaklaşması ise tavana ulaşıldığını ve istek hızının host’un emebileceğini aştığını gösteren sinyaldir.

nginx sıkılaştırmasının dürüst sınırı

Buradaki her şey uygulama kenarındaki istek oranı ve bağlantı durumu tükenmesine karşıdır. İki durum bunun dışında kalır.

Birincisi hat doluluğudur. Hacim sunucunun önündeki boruyu doldurursa nginx paketleri hiç almaz ve hiçbir direktif geçerli olmaz.

Yerinde katmanın yardımcı olamadığı sınır 10 Gbps erişim hattınız Hat zaten doymuş — yalnızca yukarı akış Yerinde cihaz azaltır 2 Gbps 8 Gbps 25 Gbps 120 Gbps 1 Tbps+ Saldırı hacmi (logaritmik ölçek)
Hat kapasitesinin altında nginx'in limitlerinin payı vardır; üstünde hiçbir direktifin anlamı kalmaz.

İkincisi nginx’in altındaki her şeydir: çekirdeğin SYN kuyrukları, conntrack tablosu ve tanıtıcıları. Bir istek bunlardan geçmeden nginx’e hiç ulaşmaz. Bunlar Linux sıkılaştırma rehberinin konusudur ve nginx sıkılaştırması onların zaten yerinde olduğunu varsayar. Hattın üstünde cevap şebeke katmanıdır. nginx, uygulama kenarını o katman devreye girene kadar ayakta tutar. İşi budur ve işinden fazlası değildir.

Uygulama sırası

  1. stub_status’ı ve genişletilmiş log’u etkinleştirin, bir haftalık temel ölçü kaydedin.
  2. worker_connections ve worker_rlimit_nofile’ı ayarlayın, işletim sistemi limitinin bunları aştığını doğrulayın.
  3. Önde herhangi bir proxy varsa, tek bir limit yazmadan önce real_ip’i düzeltin.
  4. limit_req ve limit_conn bölgelerini limit_req_dry_run on ile ekleyin, bir hafta gözleyin.
  5. Devreye almak için dry-run’ı kapatın, 429 oranını izleyin.
  6. Timeout’ları ve boyut limitlerini ayarlayın.
  7. Dört sinyali izlemeye bağlayın.

Üçüncü adım limitlerden önce gelir, bunun bilinçli bir sebebi vardır. Yanlış adres üzerine anahtarlanan bir oran limiti, limitsiz durumdan daha kötüdür, çünkü hiçbir şeyi korumadığı hâlde koruma gibi görünür.

Sık sorulan sorular

nginx zaten Slowloris'e bağışık değil mi?
Büyük ölçüde bağışıktır, ama bunu tam olarak söylemek gerekir. Slowloris her yavaş bağlantı için bir worker iş parçacığını meşgul ederek çalışır. nginx bir olay döngüsü kullanır, bu yüzden yavaş bağlantı bir iş parçacığına değil bir dosya tanıtıcısına ve biraz belleğe mal olur; binlercesi, iş parçacığı başına bağlantı açan bir sunucuya vereceğinden çok daha az zarar verir. Ama "çok daha az" sıfır değildir. Tanıtıcılar hâlâ sonludur, dolayısıyla client_header_timeout ve client_body_timeout hâlâ önemlidir; asılı kalan bağlantıları tahliye ederek yakın bağışıklığı gerçek bağışıklığa çeviren şey bunlardır.
limit_req burst ve nodelay mı kullanmalı, yoksa delay mı?
Çoğu genel uç nokta için burst ile nodelay. Düz limit_req, oranın üstündeki her şeyi anında reddeder ve bir sayfanın kendi varlıklarını yüklemesi gibi meşru ani yükselmeleri cezalandırır. burst, kısa bir sıçramayı emen bir kuyruk ekler. nodelay ise kuyruğa alınan istekleri araya boşluk koymadan hemen sunar, ki bir tarayıcının beklediği budur. delay ise ani yükü kaldıramayan bir arka uca trafiği yumuşatmak istediğiniz daha ender durum içindir. Oranı düşük, burst'ü cömert tutun, sonra sıkılaştırmadan önce 429 oranını okuyun.
$binary_remote_addr nedir, neden $remote_addr değil?
İkisi de bölgeyi istemci adresi üzerine anahtarlar. $binary_remote_addr adresi bir dize yerine IPv4 için 4 baytta saklar, böylece sabit bir bölge boyutu çok daha fazla girdi tutar. 10 MB'lık bir bölge, ikili biçimle yaklaşık 160.000 IPv4 girdisi tutar. Asıl mesele kapasitedir: çok sayıda adresten gelen bir saldırıda bölge dolmamalıdır, yoksa yeni meşru istemciler saldırganlarla birlikte tahliye edilir. Bu yüzden oran ve bağlantı bölgelerini her zaman ikili biçim üzerine anahtarlayın.
Gerçek kullanıcıları kesmeden bir oran limitini nasıl devreye alırım?
limit_req_dry_run on ile. Sınırlama mantığının tamamını çalıştırır ve neyi reddedeceğini error log'a yazar, ama her isteği geçirir. Temsili bir hafta boyunca açık bırakırsınız, hangi istemcilerin hangi oranda sınırlanacağını okur, bunların gerçek trafiğiniz olmadığını doğrular ve ancak o zaman kapatıp kuralı devreye alırsınız. Bir limit_req'i doğrudan devreye almak, üstelik bir rehberdeki sayıya göre ayarlamak, yoğun bir sabahta kendi ana sayfanızı sınırlamanın yoludur.
Bir yük dengeleyici veya CDN arkasında ne bozulur?
Anahtar bozulur. nginx bir proxy arkasındaysa $binary_remote_addr proxy'nin adresidir, dolayısıyla her istemci tek bir oran kovasını paylaşır ve limit anlamsızlaşır. Önce gerçek istemci IP'sini yapılandırmanız gerekir: proxy aralıkları için set_real_ip_from ve gönderdiği başlık için real_ip_header. Böylece bölge gerçek istemci üzerine anahtarlanır. Bunu yanlış yapmak, bir oran limitinin ya hiçbir şey yapmamasının ya da herkesi aynı anda kısmasının en yaygın sebebidir.
Bu direktifler hacimsel bir saldırıyı durdurur mu?
Hayır. Saldırı sunucunun önündeki hattı doldurursa nginx paketleri hiç almaz ve hiçbir direktif geçerli olmaz. Buradaki her şey uygulama kenarındaki istek oranı ve bağlantı durumu tükenmesine karşıdır. Hat kapasitesinin üzerindeki hacim bir şebeke katmanı sorunudur ve nginx.conf içinde çözülmez.

Yayım: Ağustos 2026

Bu rehber, üreticiler yeni modeller ve fiyatlandırma açıkladıkça güncellenir. Üreticileri nasıl karşılaştırıyoruz