Nginx ile Bot Koruması: Kötü Trafiği Filtreleme Yöntemleri

Her gece sunucu loglarına bakıp onlarca farklı IP adresinden gelen anlamsız istekleri görüyorsanız, yalnız değilsiniz. Modern web altyapısında bot trafiği toplam internet trafiğinin yaklaşık %40’ını oluşturuyor ve bunun büyük bir kısmı kötü niyetli. Nginx kullanıyorsanız, bu trafiği sunucunuza ulaşmadan önce filtrelemek için elinizde oldukça güçlü araçlar var. Bu yazıda gerçek dünya senaryolarından yola çıkarak Nginx’te bot koruması nasıl kurulur, bad traffic nasıl filtrelenir, adım adım inceleyeceğiz.

Bot Trafiği Neden Bu Kadar Önemli?

Önce şunu netleştirelim: her bot kötü değil. Google, Bing, DuckDuckGo gibi arama motorlarının botları sitenizin indexlenmesi için gerekli. Ama onların yanı sıra sunucunuzu yoran, veritabanınızı sorgulayan, API endpoint’lerinizi brute-force’a tutan, içeriklerinizi scrape eden yüzlerce kötü niyetli bot var.

Bir e-ticaret sitesi yöneticisi olduğunuzu düşünün. Rakip firma ürün fiyatlarınızı saatte bir scrape ediyor, login sayfanıza credential stuffing saldırısı düzenleniyor ve sahte kayıt botları veritabanınızı şişiriyor. Tüm bu trafik hem sunucu kaynaklarınızı tüketiyor hem de güvenlik açığı oluşturuyor.

Nginx, bu sorunları çözmek için birkaç farklı katmanda çalışabilir:

  • User-Agent filtreleme: Bilinen kötü botları UA string’e göre bloklama
  • Rate limiting: IP bazlı istek hızı sınırlama
  • Geo-blocking: Ülke bazlı erişim kısıtlama
  • IP reputation listeleri: Bilinen kötü IP adreslerini bloklama
  • Request pattern analizi: Şüpheli istek kalıplarını tespit etme
  • Connection throttling: Bağlantı sayısını sınırlama

Nginx Konfigürasyon Yapısını Anlamak

Filtreleme kurallarını yazmadan önce Nginx’in konfigürasyon hiyerarşisini kavramak gerekiyor. http, server ve location bloklarının her birinde farklı direktifler çalışır. Bot koruması için çoğunlukla http bloğunda global tanımlamalar yapıp, server bloklarında bunları kullanıyoruz.

# /etc/nginx/nginx.conf temel yapısı
http {
    # Global map ve limit zone tanımlamaları buraya gelir
    
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Bütün özel filtreleme kurallarımızı /etc/nginx/conf.d/bot-protection.conf gibi ayrı bir dosyada tutmanızı öneririm. Bu sayede ana konfigürasyonunuz temiz kalır ve sorun çıkınca kolayca devre dışı bırakabilirsiniz.

User-Agent Bazlı Bot Filtreleme

En temel ama etkili yöntemlerden biri User-Agent filtreleme. Kötü niyetli botların büyük çoğunluğu ya tanınabilir bir UA string kullanıyor ya da hiç UA göndermiyorlar.

# /etc/nginx/conf.d/bot-protection.conf

map $http_user_agent $bad_bot {
    default 0;
    
    # Boş user-agent - neredeyse her zaman kötü niyetli
    ""  1;
    
    # Bilinen scraper ve kötü botlar
    ~*scrapy                    1;
    ~*ahrefsbot                 1;
    ~*semrushbot                1;
    ~*dotbot                    1;
    ~*blexbot                   1;
    ~*mj12bot                   1;
    ~*rogerbot                  1;
    ~*masscan                   1;
    ~*nikto                     1;
    ~*sqlmap                    1;
    ~*nmap                      1;
    ~*zgrab                     1;
    ~*python-requests           1;
    ~*go-http-client            1;
    ~*curl/                     1;
    ~*libwww-perl               1;
    ~*java/                     1;
    ~*wget/                     1;
    
    # Özel tehdit istihbaratı - kendi listenizi ekleyin
    ~*badbot                    1;
    ~*harvest                   1;
    ~*extract                   1;
}

Burada dikkat edilmesi gereken bir nokta: curl ve wget‘i tamamen bloklarsanız meşru API istemcilerini de etkileyebilirsiniz. Production ortamında bu kararı iş gereksinimlerinize göre verin. Eğer API’niz harici servislere açıksa, bu araçları whitelist mekanizmasıyla yönetmek daha sağlıklı.

Sonra server bloğunuzda bu map’i kullanın:

server {
    listen 443 ssl;
    server_name ornek.com www.ornek.com;
    
    # Bot kontrolü
    if ($bad_bot = 1) {
        return 444;  # Nginx'e özgü - bağlantıyı sessizce kapatır
    }
    
    # ... geri kalan konfigürasyon
}

444 response kodu Nginx’e özel, hiçbir HTTP response göndermeden bağlantıyı kesiyor. Bu hem kaynak tüketimini azaltıyor hem de botu “başarısız” olduğu konusunda bilgilendirmiyorsunuz. Alternatif olarak 403 de kullanabilirsiniz ama botu bilgilendirmiş olursunuz.

Rate Limiting ile Aşırı İstek Koruması

User-Agent filtreleme ilk savunma hattı, ama akıllı botlar bunu kolayca atlayabilir. Rate limiting daha katmanlı bir koruma sağlar.

# /etc/nginx/conf.d/rate-limiting.conf

# Genel web trafiği için limit zone
limit_req_zone $binary_remote_addr zone=general:10m rate=30r/m;

# Login endpoint için çok daha sıkı limit
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

# API endpoint'leri için
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/m;

# Kayıt sayfası için
limit_req_zone $binary_remote_addr zone=register:10m rate=3r/m;

# Search endpoint için
limit_req_zone $binary_remote_addr zone=search:10m rate=20r/m;

Zone boyutu hakkında: 1MB yaklaşık 16.000 IP adresini tutabilir. 10MB çoğu site için yeterli ama yoğun trafikli bir API gateway için 50MB veya daha fazlası gerekebilir.

Şimdi bu zone’ları server bloğunda kullanalım:

server {
    listen 443 ssl;
    server_name api.ornek.com;
    
    # Genel rate limit
    limit_req zone=general burst=50 nodelay;
    limit_req_status 429;
    
    # Login endpoint - çok sıkı
    location /auth/login {
        limit_req zone=login burst=3 nodelay;
        limit_req_status 429;
        
        proxy_pass http://backend_login;
    }
    
    # Kayıt endpoint
    location /auth/register {
        limit_req zone=register burst=2 nodelay;
        limit_req_status 429;
        
        proxy_pass http://backend_register;
    }
    
    # API endpoint'leri
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        limit_req_status 429;
        
        proxy_pass http://backend_api;
    }
    
    # Search - ayrı zone
    location /api/search {
        limit_req zone=search burst=10 nodelay;
        limit_req_status 429;
        
        proxy_pass http://backend_search;
    }
}

burst parametresi anlık yoğunluğa izin verir. nodelay ise burst içindeki istekleri geciktirmek yerine hemen işler ama limiti aşanları reddeder. Bu kombinasyon gerçek kullanıcılara daha iyi deneyim sunarken botları etkili biçimde bloklar.

Bağlantı Sınırlama

Rate limiting istek bazlıyken, bağlantı sınırlama aynı anda kaç açık bağlantı olabileceğini kontrol eder. Slowloris gibi saldırılara karşı etkilidir.

# /etc/nginx/conf.d/connection-limiting.conf

# Bağlantı zone tanımlaması
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

# Server bloğu içinde
server {
    listen 443 ssl;
    server_name ornek.com;
    
    # Tek IP'den max 20 eş zamanlı bağlantı
    limit_conn conn_limit 20;
    limit_conn_status 429;
    
    # Yavaş bağlantıları sonlandır - Slowloris koruması
    client_body_timeout 10s;
    client_header_timeout 10s;
    keepalive_timeout 30s;
    send_timeout 10s;
    
    # Büyük body'leri reddet - DDoS amplification önlemi
    client_max_body_size 10m;
    client_body_buffer_size 128k;
}

Gelişmiş Map Tabanlı Filtreleme

Birden fazla kriteri birleştirerek daha akıllı bir filtreleme sistemi kurabilirsiniz. Mesela hem User-Agent hem de request pattern’ine bakarak karar vermek gibi.

# /etc/nginx/conf.d/advanced-filtering.conf

# Şüpheli URI pattern'lerini tespit et
map $request_uri $suspicious_uri {
    default 0;
    
    # Yaygın güvenlik açığı tarama pattern'leri
    ~*.(php|asp|aspx|jsp)$     1;
    ~*/wp-admin                  1;
    ~*/wp-login                  1;
    ~*/phpMyAdmin                1;
    ~*/phpmyadmin                1;
    ~*.env                      1;
    ~*.git                      1;
    ~*/etc/passwd                1;
    ~*/proc/self                 1;
    ~*../                      1;  # Path traversal
    ~*union.*select              1;  # SQL injection
    ~*<script                    1;  # XSS denemesi
    ~*eval(                     1;
    ~*/xmlrpc.php               1;
    ~*/config.php               1;
}

# HTTP method kontrolü
map $request_method $bad_method {
    default 0;
    CONNECT 1;
    TRACE   1;
    TRACK   1;
}

# Referrer kontrolü - boş referrer ile direkt erişimi kontrol et
# (API için bu yaklaşım kullanılmaz, sadece web sayfaları için)
map $http_referer $suspicious_referer {
    default 0;
    ~*semalt     1;
    ~*buttons-for-website 1;
    ~*free-share-buttons  1;
}

# Birleşik skor hesapla
map "$bad_bot:$suspicious_uri:$bad_method" $threat_score {
    default         0;
    "1:0:0"        10;  # Sadece kötü bot UA
    "0:1:0"        5;   # Sadece şüpheli URI
    "0:0:1"        10;  # Kötü method
    "1:1:0"        20;  # Bot + şüpheli URI
    "1:0:1"        20;  # Bot + kötü method
    "1:1:1"        30;  # Her şey kötü
}

Bu map’i server bloğunda şöyle kullanabilirsiniz:

server {
    listen 443 ssl;
    server_name ornek.com;
    
    # Şüpheli URI'lere direkt 404 dön - bilgi verme
    if ($suspicious_uri = 1) {
        return 404;
    }
    
    # Kötü HTTP method'larını reddet
    if ($bad_method = 1) {
        return 405;
    }
    
    # Kötü bot ise 444 ile kes
    if ($bad_bot = 1) {
        return 444;
    }
}

Geo-Blocking ile Ülke Bazlı Filtreleme

Eğer hizmetiniz belirli ülkelere yönelikse, diğer ülkelerden gelen trafiği kısıtlamak hem güvenlik hem de performans açısından mantıklı. Bunun için ngx_http_geoip2_module modülü gerekiyor.

Önce MaxMind GeoLite2 veritabanını ve modülü kuralım:

# Ubuntu/Debian için
apt install nginx-module-geoip2

# MaxMind hesabı açıp ücretsiz GeoLite2 veritabanını indirin
# https://dev.maxmind.com/geoip/geolite2-free-geolocation-data

# mmdbinspect kurulumu (opsiyonel, test için)
apt install mmdb-bin

# Nginx.conf'a modülü yükle
# nginx.conf en üstüne ekle:
load_module modules/ngx_http_geoip2_module.so;

Konfigürasyon:

# /etc/nginx/conf.d/geo-blocking.conf

# GeoIP2 modülü ile ülke tespiti
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
    $geoip2_data_country_code country iso_code;
    $geoip2_data_country_name country names en;
}

# İzin verilen ülkeler (Türkiye odaklı bir servis için)
map $geoip2_data_country_code $allowed_country {
    default         0;
    TR              1;  # Türkiye
    DE              1;  # Almanya (Türk diaspora)
    NL              1;  # Hollanda
    AT              1;  # Avusturya
    GB              1;  # İngiltere
    US              1;  # Amerika
}

# Ya da tersini yapın - belirli ülkeleri bloklayın
map $geoip2_data_country_code $blocked_country {
    default         0;
    CN              1;  # Çin
    RU              1;  # Rusya
    KP              1;  # Kuzey Kore
    IR              1;  # İran
}

Server bloğunda kullanımı:

server {
    listen 443 ssl;
    server_name ornek.com;
    
    # Bloklanmış ülkelerden gelen trafiği reddet
    if ($blocked_country = 1) {
        return 403;
    }
    
    # Ya da sadece belirli ülkelere izin ver
    # if ($allowed_country = 0) {
    #     return 403;
    # }
    
    # API endpoint'leri için daha katı geo kural
    location /api/admin/ {
        if ($geoip2_data_country_code != "TR") {
            return 403;
        }
        proxy_pass http://backend_admin;
    }
}

Log Tabanlı Gerçek Zamanlı İzleme

Filtreleme kurallarınız çalışıyor mu? Hangi botlar en çok çarpıyor? Bunları görmek için Nginx log formatını zenginleştirin:

# /etc/nginx/nginx.conf içindeki http bloğu

http {
    # Zenginleştirilmiş log formatı
    log_format bot_detection '$remote_addr - $remote_user [$time_local] '
                             '"$request" $status $body_bytes_sent '
                             '"$http_referer" "$http_user_agent" '
                             '$request_time $upstream_response_time '
                             'geoip="$geoip2_data_country_code" '
                             'bad_bot="$bad_bot" '
                             'suspicious_uri="$suspicious_uri" '
                             'rate_limited="$limit_req_status"';
    
    access_log /var/log/nginx/access.log bot_detection;
    error_log /var/log/nginx/error.log warn;
}

Logları analiz etmek için basit bash scriptleri:

#!/bin/bash
# /usr/local/bin/bot-stats.sh
# Günlük bot istatistikleri

LOG="/var/log/nginx/access.log"
DATE=$(date +%d/%b/%Y)

echo "=== Bot Koruma İstatistikleri - $DATE ==="
echo ""

echo "-- En Çok İstek Atan IP'ler (Top 10) --"
grep "$DATE" $LOG | awk '{print $1}' | sort | uniq -c | sort -rn | head -10

echo ""
echo "-- 444 (Bot Kesilen) İstekler --"
grep "$DATE" $LOG | grep '" 444 ' | wc -l

echo ""
echo "-- 429 (Rate Limited) İstekler --"
grep "$DATE" $LOG | grep '" 429 ' | wc -l

echo ""
echo "-- 403 (Geo/Policy Blocked) İstekler --"
grep "$DATE" $LOG | grep '" 403 ' | wc -l

echo ""
echo "-- En Yaygın Kötü User-Agent'lar --"
grep "$DATE" $LOG | grep 'bad_bot="1"' | grep -oP '"[^"]*"(?= d+ d+ ")' | 
    sort | uniq -c | sort -rn | head -10

echo ""
echo "-- Ülkelere Göre Engellenen Trafik --"
grep "$DATE" $LOG | grep '" 403 ' | grep -oP 'geoip="K[^"]+' | 
    sort | uniq -c | sort -rn | head -10

Bu scripti crontab’a ekleyin:

# Sabah 8'de günlük rapor maile gönder
0 8 * * * /usr/local/bin/bot-stats.sh | mail -s "Nginx Bot Report" [email protected]

Fail2Ban ile Nginx Entegrasyonu

Nginx’in kendi rate limiting’i anlık koruya sağlıyor ama aynı IP tekrar tekrar denemeye devam edebilir. Fail2Ban ile kalıcı ban mekanizması kurabilirsiniz.

# /etc/fail2ban/filter.d/nginx-bot.conf

[Definition]
failregex = ^<HOST> .* "(GET|POST|HEAD).*" (444|429|403) .*$
ignoreregex =

# /etc/fail2ban/jail.d/nginx-bot.conf

[nginx-bot]
enabled  = true
port     = http,https
filter   = nginx-bot
logpath  = /var/log/nginx/access.log
maxretry = 20
findtime = 300
bantime  = 86400
action   = iptables-multiport[name=nginx-bot, port="http,https", protocol=tcp]

Fail2Ban’ı başlatın:

systemctl restart fail2ban
fail2ban-client status nginx-bot
# Aktif ban listesini görüntüle
fail2ban-client status nginx-bot | grep "Banned IP"

Whitelist Mekanizması

Tüm bu kurallar bazen meşru trafiği de etkileyebilir. Whitelist olmadan production’a almayın.

# /etc/nginx/conf.d/whitelist.conf

# Güvenilir IP'ler - kendi ofis IP'leriniz, monitoring sistemleri vs.
geo $trusted_ip {
    default         0;
    
    # Kendi ofis IP'niz
    1.2.3.4         1;
    
    # Monitoring servisleri (Pingdom, UptimeRobot vs.)
    # Bunların IP listelerini ilgili servis dokümantasyonundan alın
    185.152.66.0/24 1;
    
    # Load balancer internal IP'leri
    10.0.0.0/8      1;
    172.16.0.0/12   1;
    192.168.0.0/16  1;
}

# Server bloğunda whitelist kontrolü
server {
    listen 443 ssl;
    server_name ornek.com;
    
    # Güvenilir IP'ler için tüm filtreleri atla
    set $skip_protection 0;
    
    if ($trusted_ip = 1) {
        set $skip_protection 1;
    }
    
    # Bot kontrolü - whitelist'tekileri atla
    if ($bad_bot$skip_protection = "10") {
        return 444;
    }
}

Gerçek Dünya Senaryosu: E-Ticaret Sitesi

Bir müşterinin e-ticaret sitesinde karşılaştığım senaryoyu paylaşayım. Site günde yaklaşık 50.000 meşru ziyaretçi alıyordu ama Nginx logları 200.000’in üzerinde istek gösteriyordu. Aradaki fark tamamen bot trafiğiydi.

Analiz ettiğimizde şunları tespit ettik:

  • Bir scraper rakip fiyatları 15 dakikada bir topluyordu
  • Credential stuffing saldırısı login sayfasına saniyede 30 istek atıyordu
  • Sahte kayıt botları günde 500’den fazla hesap oluşturuyordu
  • Çeşitli güvenlik açığı scanner’ları sürekli WordPress path’leri tarıyordu

Uyguladığımız çözüm:

# /etc/nginx/conf.d/ecommerce-protection.conf

# Fiyat scraper'ını tespit et - ürün sayfalarına çok hızlı giriyor
limit_req_zone $binary_remote_addr zone=product_pages:20m rate=10r/m;

# Login koruması
limit_req_zone $binary_remote_addr zone=ecom_login:10m rate=3r/m;

# Arama koruması - botlar genelde tüm kategoriyi geziyor
limit_req_zone $binary_remote_addr zone=ecom_search:10m rate=15r/m;

# Checkout - çok kritik, çok sıkı
limit_req_zone $binary_remote_addr zone=checkout:10m rate=5r/m;

server {
    listen 443 ssl;
    server_name magazam.com;
    
    # Whitelist check önce
    if ($trusted_ip = 1) {
        set $skip_all 1;
    }
    
    # Kötü botları kes
    if ($bad_bot$skip_all = "10") {
        return 444;
    }
    
    # Güvenlik scanner pattern'leri
    if ($suspicious_uri = 1) {
        return 404;
    }
    
    # Ürün listeleme - scraper koruması
    location ~* ^/kategori/ {
        limit_req zone=product_pages burst=5 nodelay;
        proxy_pass http://backend;
    }
    
    location ~* ^/urun/ {
        limit_req zone=product_pages burst=3 nodelay;
        proxy_pass http://backend;
    }
    
    # Login - credential stuffing koruması
    location = /giris {
        limit_req zone=ecom_login burst=2 nodelay;
        
        # Aynı IP'den art arda 401 gelince ekstra log
        log_subrequest on;
        
        proxy_pass http://backend;
    }
    
    # Kayıt sayfası - fake account koruması
    location = /kayit {
        limit_req zone=register burst=1 nodelay;
        proxy_pass http://backend;
    }
    
    # Checkout - en kritik nokta
    location ~* ^/odeme/ {
        limit_req zone=checkout burst=2 nodelay;
        limit_conn conn_limit 5;
        proxy_pass http://backend;
    }
}

Bu konfigürasyonu devreye aldıktan iki hafta sonra sunucu yükü %35 düştü ve sahte hesap oluşturma neredeyse sıfırlandı.

Konfigürasyonu Test Etmek

Yazdığınız kuralların çalışıp çalışmadığını test edin. Ama önce konfigürasyonu doğrulayın:

# Konfigürasyon syntax kontrolü
nginx -t

# Daha ayrıntılı çıktı için
nginx -T | grep -A5 "bad_bot"

# Reload (sıfır downtime ile)
nginx -s reload

# Kendi kurallarınızı test edin
# Kötü bot UA simülasyonu
curl -A "Scrapy/1.0" https://ornek.com/
# 444 veya 403 döndürmeli

# Rate limit testi
for i in {1..10}; do curl -o /dev/null -s -w "%{http_code}n" https://ornek.com/giris; done
# İlk birkaç 200, sonralar 429 döndürmeli

# Şüpheli URI testi
curl https://ornek.com/wp-admin
# 404 döndürmeli (WordPress kullanmıyor olsanız bile)

Sonuç

Nginx ile bot koruması katmanlı bir yaklaşım gerektiriyor. Tek bir kural her şeyi çözmez; User-Agent filtreleme, rate limiting, connection sınırlama, geo-blocking ve davranışsal analizi birlikte kullandığınızda gerçek anlamda etkili bir savunma hattı kurmuş olursunuz.

Dikkat edilmesi gereken en önemli nokta: agresif kurallar meşru kullanıcıları da etkiler. Whitelist mekanizmasını mutlaka kurun, logları düzenli izleyin ve kurallarınızı gerçek trafik verilerine göre kalibre edin. Production’a almadan önce bir staging ortamında test edin.

Bot koruması statik bir iş değil. Botlar sürekli evrim geçiriyor, yeni pattern’ler ortaya çıkıyor. Fail2Ban entegrasyonu, düzenli log analizi ve istatistik raporlaması bu adaptasyonu kolaylaştırır. Zamanla kendi “bad actor” listenizi oluşturacaksınız ve bu en değerli kaynağınız olacak.

Son olarak, Nginx’in bu yetenekleri ücretsiz ve açık kaynak. Cloudflare Bot Management veya benzeri ticari ürünlere para vermeden önce Nginx ile ne kadar çok şey yapabileceğinizi görünce şaşıracaksınız.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir