Sunucunu kurup internete açtığın an, logları izlemeye başlarsan göreceksin: dakikalar içinde brute force denemeleri, tarayıcı botları ve kötü niyetli istekler akmaya başlıyor. Özellikle Nginx ve Apache gibi web sunucularına yönelik saldırılar hem çok yaygın hem de otomatize edilmiş durumda. İşte bu noktada fail2ban devreye giriyor. Fail2ban, log dosyalarını izleyerek belirlediğin kurallara uyan IP adreslerini otomatik olarak yasaklayan, hafif ama son derece etkili bir araç.
Bu yazıda fail2ban’ı sıfırdan kurup hem Nginx hem de Apache için gerçek dünya senaryolarına uygun şekilde nasıl yapılandıracağını adım adım göstereceğim. Sadece “şunu kopyala yapıştır” değil, her ayarın ne işe yaradığını da anlayarak ilerleyeceğiz.
Fail2ban Nedir ve Nasıl Çalışır
Fail2ban Python ile yazılmış bir daemon. Temel mantığı şu: log dosyalarını düzenli aralıklarla tarar, belirlediğin regex patternlerine uyan başarısız giriş denemelerini veya şüpheli aktiviteleri sayar, belirlediğin eşiği aşan IP adreslerini ise iptables, nftables veya ufw gibi firewall araçlarına banlar.
Birkaç temel kavramı baştan netleştirelim:
- Filter: Log satırlarını analiz eden regex tanımları. Hangi satırların “başarısız deneme” sayılacağını belirler.
- Jail: Bir filter ile action’ı birleştiren yapılandırma bloğu. “Bu log için şu filtreyi kullan, eşiği aşarsa şu action’ı çalıştır” der.
- Action: Ban işlemini gerçekleştiren komut. Genellikle iptables kuralı ekler.
- bantime: IP’nin kaç saniye yasaklı kalacağı.
- findtime: Başarısız denemelerin kaç saniye içinde sayılacağı.
- maxretry: findtime içinde kaç başarısız denemeden sonra ban uygulanacağı.
Kurulum
Debian/Ubuntu tabanlı sistemlerde:
sudo apt update
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
RHEL/CentOS/Rocky Linux sistemlerde:
sudo dnf install epel-release -y
sudo dnf install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Kurulumdan sonra fail2ban’ın düzgün çalıştığını doğrula:
sudo systemctl status fail2ban
sudo fail2ban-client status
Temel Yapılandırma Felsefesi
Fail2ban’ın yapılandırma dosyaları /etc/fail2ban/ altında. Burada önemli bir kural var: /etc/fail2ban/jail.conf dosyasını doğrudan düzenleme. Bu dosya paket güncellemelerinde üzerine yazılır. Bunun yerine jail.local dosyası oluştur:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Ya da sıfırdan da oluşturabilirsin, daha temiz olur:
sudo nano /etc/fail2ban/jail.local
Aynı kural filter dosyaları için de geçerli. /etc/fail2ban/filter.d/ altındaki .conf dosyaları yerine .local uzantılı dosyalar oluşturmalısın.
Global Ayarlar
jail.local dosyasının başına global varsayılan değerleri tanımla. Bu değerler tüm jail’ler için geçerli olur, jail bazında override edebilirsin:
[DEFAULT]
# Hiçbir zaman banlanmayacak IP'ler (kendi IP'n, monitoring sistemlerin)
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 10.0.0.0/8
# Ban süresi: 1 saat (saniye cinsinden veya zaman suffixleri)
bantime = 3600
# Bu süre içinde maxretry kadar başarısız deneme olursa ban
findtime = 600
# Kaç başarısız denemede ban
maxretry = 5
# Backend: systemd, auto, pyinotify, polling
backend = systemd
# Email bildirimleri için (opsiyonel)
destemail = [email protected]
sendername = Fail2Ban
mta = sendmail
# Varsayılan action: ban + email veya sadece ban
action = %(action_)s
ignoreip ayarı kritik. Kendi IP adresini mutlaka buraya ekle, yoksa yanlışlıkla kendini kilitleyebilirsin. VPN kullanıyorsan VPN IP bloğunu da ekle.
bantime için -1 değeri kalıcı ban anlamına gelir. Özellikle agresif saldırılar için kullanılabilir ama dikkatli ol.
Nginx Yapılandırması
Nginx HTTP Auth Koruması
Nginx’te basic auth veya giriş sayfası koruması için önce filter dosyasını oluştur:
sudo nano /etc/fail2ban/filter.d/nginx-http-auth.local
[Definition]
failregex = ^ [error] d+#d+: *d+ user "(?:[^"]+|.*?)":? (?:password mismatch|was not found in "[^"]*"), client: <HOST>, server: S*, request: "S+ S+ HTTP/d+", host: "S+"
^ [error] d+#d+: *d+ no user/password was provided for basic authentication, client: <HOST>, server: S*, request: "S+ S+ HTTP/d+", host: "S+"
ignoreregex =
Şimdi jail.local dosyasına bu jail’i ekle:
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600
findtime = 300
Nginx 4xx Hata Koruması
Scanner’lar ve botlar genellikle var olmayan sayfalara, admin panellerine, /wp-admin, /.env, /config.php gibi path’lere istek gönderir. Bu istekler 404 döndürür. Çok fazla 404 isteği gönderen IP’leri banlamak için:
sudo nano /etc/fail2ban/filter.d/nginx-4xx.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD).*HTTP.*" (400|401|403|404|405|444) .*$
ignoreregex = ^<HOST> -.*"(GET|POST) /health.*HTTP.*" 404
^<HOST> -.*"GET /favicon.ico HTTP.*" 404
ignoreregex kısmına healthcheck endpoint’leri ve favicon gibi meşru 404’leri ekle, yoksa monitoring araçların veya tarayıcılar banlanabilir.
jail.local‘e ekle:
[nginx-4xx]
enabled = true
filter = nginx-4xx
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 20
bantime = 7200
findtime = 60
Bu jail için maxretry‘yi biraz yüksek tuttum çünkü 404 meşru kullanıcılarda da oluşabilir. 60 saniye içinde 20 tane 404 alan birinin büyük ihtimalle scanner olduğunu söyleyebiliriz.
Nginx Rate Limit Koruması
Nginx’te limit_req_zone kullandıysan bu zone’u aşan istekler error log’a düşer. Bunu da fail2ban ile yakalayabilirsin:
sudo nano /etc/fail2ban/filter.d/nginx-req-limit.conf
[Definition]
failregex = limiting requests, excess:.* by zone.*client: <HOST>
ignoreregex =
[nginx-req-limit]
enabled = true
filter = nginx-req-limit
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 10
bantime = 7200
findtime = 60
Apache Yapılandırması
Apache Auth Koruması
Apache’de zaten apache-auth filter’ı hazır geliyor, sadece jail tanımlaması yapman yeterli:
[apache-auth]
enabled = true
filter = apache-auth
port = http,https
logpath = /var/log/apache2/error.log
maxretry = 3
bantime = 3600
findtime = 300
Apache Overflows ve Scanner Koruması
Apache’ye yönelik overflow denemelerini ve bilinen kötü niyetli bot davranışlarını yakalamak için:
[apache-overflows]
enabled = true
filter = apache-overflows
port = http,https
logpath = /var/log/apache2/error.log
maxretry = 2
bantime = 86400
findtime = 600
[apache-noscript]
enabled = true
filter = apache-noscript
port = http,https
logpath = /var/log/apache2/access.log
maxretry = 6
bantime = 86400
findtime = 600
[apache-badbots]
enabled = true
filter = apache-badbots
port = http,https
logpath = /var/log/apache2/access.log
bantime = 172800
maxretry = 1
findtime = 86400
apache-badbots için maxretry = 1 ayarladım çünkü bilinen kötü niyetli bot user-agent’larını kullanan biri için tek bir istek bile yeterli sebep. Bu filter /etc/fail2ban/filter.d/apache-badbots.conf içinde zaten tanımlı geliyor, içine bakarak hangi botları kapsadığını görebilirsin.
Özel Apache 4xx Filter
Nginx için yaptığımız gibi Apache için de 4xx bazlı bir filter oluşturalım:
sudo nano /etc/fail2ban/filter.d/apache-4xx.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD).*HTTP.*" (400|401|403|404|405) .*$
ignoreregex = ^<HOST> -.*"GET /server-status.*HTTP.*" 403
^<HOST> -.*"GET /favicon.ico HTTP.*" 404
^<HOST> -.*"GET /.well-known/.*HTTP.*" 404
.well-known path’ini ignoreregex’e eklemeyi unutma, Let’s Encrypt validasyonları bu path’i kullanır ve 404 dönebilir.
[apache-4xx]
enabled = true
filter = apache-4xx
port = http,https
logpath = /var/log/apache2/access.log
maxretry = 15
bantime = 7200
findtime = 60
Log Format Kontrolü
Filter’ların düzgün çalışması için web sunucunun log formatının fail2ban’ın beklediği formata uyması gerekiyor. Nginx’in varsayılan combined log formatı genellikle sorunsuz çalışır:
# Nginx log formatı kontrol
sudo tail -5 /var/log/nginx/access.log
# Apache log formatı kontrol
sudo tail -5 /var/log/apache2/access.log
Eğer custom log format kullanıyorsan filter regex’ini buna göre ayarlaman gerekebilir. Filter’ı test etmeden önce bu adımı atlama.
Filter Test Etme
Jail’leri aktif etmeden önce filter’larını test et. Bu hem hata yakalamak hem de gerçekten istediğin satırları yakalayıp yakalamadığını görmek için çok önemli:
# Belirli bir filter'ı log dosyasına karşı test et
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf
# Detaylı çıktı için
sudo fail2ban-regex --print-all-matched /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf
Çıktıda kaç satırın eşleştiğini, kaç satırın ignore edildiğini göreceksin. Eğer hiç eşleşme yoksa ya log formatın farklıdır ya da regex yanlış yazılmıştır.
Yapılandırmayı Uygulama ve Yönetim
Tüm değişikliklerden sonra fail2ban’ı yeniden başlatmak yerine reload et, daha temiz:
sudo fail2ban-client reload
# Belirli bir jail'i reload etmek için
sudo fail2ban-client reload nginx-4xx
# Tüm aktif jail'leri listele
sudo fail2ban-client status
# Belirli bir jail'in durumunu gör
sudo fail2ban-client status nginx-4xx
# Banlı IP'leri listele
sudo fail2ban-client status nginx-4xx | grep "Banned IP"
Bir IP’yi manuel olarak banlamak veya ban kaldırmak:
# Manuel ban
sudo fail2ban-client set nginx-4xx banip 192.168.1.100
# Ban kaldırma (unban)
sudo fail2ban-client set nginx-4xx unbanip 192.168.1.100
# Tüm jail'lerde belirli bir IP'yi unban et
for jail in $(sudo fail2ban-client status | grep "Jail list" | sed 's/.*://;s/,//g'); do
sudo fail2ban-client set $jail unbanip 192.168.1.100 2>/dev/null
done
Son komutu bir script olarak kaydedip kullanmak, özellikle false positive durumlarında hayat kurtarır.
Gerçek Dünya Senaryosu: WordPress Saldırısı
Diyelim ki WordPress çalıştıran bir sunucun var ve /wp-login.php ile /xmlrpc.php üzerinden sürekli brute force geliyor. Bu çok yaygın bir senaryo.
sudo nano /etc/fail2ban/filter.d/wordpress.conf
[Definition]
failregex = ^<HOST> -.*"POST /(wp-login|xmlrpc).php HTTP.*" (200|403|429) .*$
^<HOST> -.*"GET /wp-login.php?.*HTTP.*" (200|302) .*$
ignoreregex =
[wordpress]
enabled = true
filter = wordpress
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 86400
findtime = 300
Burada ilginç bir nokta: başarılı login’ler de 200 döndürür. Ama 300 saniye içinde 5 kez login denemesi yapan biri zaten brute force yapıyordur. Meşru bir kullanıcı bu kadar hızlı deneme yapmaz.
Jail Durumunu İzleme ve Log Takibi
# Fail2ban logunu canlı takip et
sudo tail -f /var/log/fail2ban.log
# Son banlanan IP'leri göster
sudo grep "Ban " /var/log/fail2ban.log | tail -20
# IP bazlı ban sayılarını say
sudo grep "Ban " /var/log/fail2ban.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head -20
Son komut hangi IP’nin kaç kez banlandığını gösterir. Çok tekrar eden IP’ler için kalıcı ban veya ISP’ye abuse bildirimi düşünebilirsin.
Recidive Jail: Tekrar Banlananlara Daha Sert Muamele
Bir IP defalarca banlanıp açılıyorsa, muhtemelen bot döngüsü içinde. recidive jail’i bu IP’leri daha uzun süre banlar:
[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
action = %(action_)s
bantime = 604800 ; 1 hafta
findtime = 86400 ; 1 günlük sürede
maxretry = 3 ; 3 kez banlanırsa 1 hafta yasak
recidive filter’ı fail2ban kendi log dosyasını izler. Başka bir jail tarafından 24 saat içinde 3 kez banlanan bir IP 1 hafta boyunca yasaklanır. Bu özellikle persistent saldırganlar için çok etkili.
Action Özelleştirme
Varsayılan action sadece iptables ban uygular. Bunu genişletebilirsin. Örneğin hem ban uygula hem de email gönder:
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600
action = %(action_mwl)s
%(action_)s: Sadece ban %(action_mw)s: Ban + whois + email %(action_mwl)s: Ban + whois + log satırları + email
Email bildirimleri için mail sunucusunun kurulu olması gerekiyor. Basit bir test için mailutils veya sendmail yeterli.
Sistemin Sağlığını Kontrol Etme
Fail2ban düzgün çalışıyor mu, gerçekten koruma sağlıyor mu? Bunu doğrulamak için:
# Aktif iptables kurallarını kontrol et
sudo iptables -L f2b-nginx-4xx -n --line-numbers
# Fail2ban'ın oluşturduğu tüm zincirleri gör
sudo iptables -L -n | grep f2b
# Istatistikleri çek
sudo fail2ban-client status | grep "Number of jail"
# Her jail için ban sayısını özetle
for jail in $(sudo fail2ban-client status | grep "Jail list" | sed 's/.*://;s/,//g'); do
banned=$(sudo fail2ban-client status $jail | grep "Currently banned" | awk '{print $NF}')
total=$(sudo fail2ban-client status $jail | grep "Total banned" | awk '{print $NF}')
echo "$jail: Aktif ban=$banned, Toplam ban=$total"
done
Performans İpuçları
Fail2ban yoğun trafik alan sunucularda zaman zaman CPU spike’ına neden olabilir. Bunu minimize etmek için:
- backend = systemd kullan: journald üzerinden log okumak dosya polling’den daha verimli.
- findtime değerini gereğinden uzun tutma: Ne kadar uzun olursa o kadar fazla log satırı memory’de tutulur.
- Çok sayıda jail yerine daha akıllı filter’lar yaz: 10 jail yerine 4-5 iyi yazılmış jail daha iyi çalışır.
- dbpurgeage değerini ayarla: Fail2ban SQLite veritabanında ban geçmişini tutar, eski kayıtları temizlemesi için bu değeri ayarla.
[DEFAULT]
dbpurgeage = 648000 ; 7.5 gün
Sık Yapılan Hatalar
Fail2ban kurarken en çok karşılaşılan hatalar:
- Kendini banlamak:
ignoreipiçine kendi IP’ni eklemeden yapılandırma test ederken. Çözüm: Her zaman önceignoreipayarla. - Log path yanlışlığı: Jail’deki
logpathgerçek log dosyasına işaret etmiyor.sudo ls -la /var/log/nginx/ile doğrula. - jail.conf üzerinde çalışmak: Güncelleme sonrası tüm değişiklikler gider. Her zaman
.localdosyaları kullan. - Filter test etmemek: Aktif etmeden önce
fail2ban-regexile test etmemek. Çalışmayan filter anlamsız bir kaynak tüketimidir. - maxretry’yi çok düşük tutmak:
maxretry = 1gibi aşırı kısıtlayıcı değerler meşru kullanıcıları da etkiler.
Sonuç
Fail2ban, doğru yapılandırıldığında web sunucularına yönelik otomatik saldırıların büyük çoğunluğunu durduran güçlü bir araç. Kurulumu basit, bakımı az, etkisi ise oldukça yüksek.
Özetleyecek olursam: Her zaman .local dosyalarında çalış, ignoreip ile kendi IP’ni koru, filter’ları aktive etmeden önce fail2ban-regex ile test et ve log formatlarının beklenenle uyuştuğundan emin ol. Recidive jail’i mutlaka aktive et çünkü persistent saldırganları otomatik olarak daha sert cezalandırması büyük kolaylık sağlıyor.
Fail2ban tek başına yeterli bir güvenlik çözümü değil elbette. WAF, mod_security, rate limiting ve düzenli güvenlik taramaları ile birlikte kullanıldığında gerçek anlamda katmanlı bir savunma oluşturursun. Ama bu araçlar arasında fail2ban’ın kurulum/fayda oranı son derece yüksek, bu yüzden her web sunucusunda bulunması gereken temel bir güvenlik katmanı olduğunu düşünüyorum.