fail2ban ile WordPress Brute Force Koruması: Jail, Filter ve Test
WordPress admin paneline günde binlerce deneme yapan botlar, sunucu kaynaklarını tüketip siteni yavaşlatıyor. fail2ban ile otomatik IP banlama nasıl kurulur?

Geçen ay bir müşterimizin WordPress sitesinde garip bir yavaşlama fark ettim. Sunucu CPU %80'lerde geziyordu, ama trafik normalden bile düşüktü. Nginx loglarına baktığımda günde 14.000'den fazla wp-login.php isteği görünce durum netleşti: botlar admin paneline brute force saldırısı yapıyordu. Cloudflare'in rate limiting'i vardı ama yetmiyordu, çünkü saldırganlar IP'lerini sürekli değiştiriyordu. O gün fail2ban'i kurup 3 saat içinde CPU kullanımı %12'ye düştü. Şimdi aynı kurulumu adım adım anlatacağım, çünkü WordPress güvenliği için firewall kadar önemli ama çok az kişi doğru kuruyor.
fail2ban, sunucunuza yapılan başarısız giriş denemelerini izleyip belirli bir eşik aşıldığında IP adresini otomatik olarak banlar. SSH, FTP, Apache, Nginx gibi servislerin loglarını okuyup pattern'lere göre aksiyon alır. WordPress için özel jail ve filter dosyaları yazarak wp-login.php ve xmlrpc.php gibi hedef noktaları koruyabilirsiniz. Ben Hollanda'daki sunucularımda varsayılan olarak kuruyorum, çünkü manuel IP banlama hem zaman kaybı hem de geç kalırsınız. Özellikle yüksek trafikli sitelerde (doktorbul.com'da 79.000 profil sayfası var) sunucu kaynaklarını korumak kritik.
Bu yazıda fail2ban'in temel mantığını, WordPress için özel jail ve filter dosyalarını, test yöntemlerini ve gerçek vaka sonuçlarını göreceğiz. Teknik bilgi gerektiriyor ama her adımı terminal komutlarıyla açıklayacağım. Hedef: 1 saatte kurulum, sonrasında sıfır manuel müdahale.
fail2ban Nasıl Çalışır: Jail, Filter ve Action Üçgeni
fail2ban üç ana bileşenden oluşur: jail (hapishane), filter (süzgeç) ve action (aksiyon). Jail, hangi servisi izleyeceğinizi tanımlar. Filter, log dosyalarında aranacak regex pattern'lerini içerir. Action, eşik aşıldığında ne yapılacağını belirler (genelde iptables ile IP banlama).
Örnek senaryo: Birisi wp-login.php'ye 5 dakikada 10 kez yanlış şifre girer. fail2ban Nginx access.log'unu okur, filter dosyasındaki regex ile "POST /wp-login.php" ve "HTTP 200" pattern'ini yakalar, sayaç 10'a ulaşınca iptables'a "bu IP'yi 1 saat banla" komutu gönderir. Kullanıcı bir sonraki istekte "403 Forbidden" alır, sunucunuz ise o IP'den gelen istekleri işlemediği için kaynak kazanır.
Debian/Ubuntu'da kurulum:
sudo apt update
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Varsayılan config dosyası /etc/fail2ban/jail.conf ama bunu direkt düzenlemiyoruz. Bunun yerine /etc/fail2ban/jail.local oluşturup override ediyoruz, çünkü paket güncellemelerinde jail.conf sıfırlanabiliyor. Ben her zaman jail.local kullanırım, böylece özel ayarlarım korunur.
Temel parametreler:
- bantime: IP ne kadar süre banlı kalacak (örnek: 3600 = 1 saat)
- findtime: Kaç saniye içinde maxretry sayısına bakılacak (örnek: 600 = 10 dakika)
- maxretry: findtime içinde kaç başarısız deneme yapılırsa ban (örnek: 5)
Örnek: bantime=3600, findtime=600, maxretry=5 demek "10 dakikada 5 başarısız deneme yapan IP'yi 1 saat banla" anlamına gelir. Ben WordPress için genelde maxretry=3 kullanırım, çünkü meşru kullanıcı 3 kez yanlış şifre girmez, bot girer.
WordPress İçin Özel Jail Dosyası Oluşturma
/etc/fail2ban/jail.local dosyasını oluşturup şu içeriği ekleyin:
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
destemail = info@futia.net
sender = fail2ban@futia.io
action = %(action_mwl)s
[wordpress-auth]
enabled = true
filter = wordpress-auth
logpath = /var/log/nginx/access.log
maxretry = 3
bantime = 7200
findtime = 600
port = http,https
[wordpress-xmlrpc]
enabled = true
filter = wordpress-xmlrpc
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400
findtime = 300
port = http,https
Burada iki jail tanımladık:
1. wordpress-auth: wp-login.php'ye yapılan brute force denemelerini yakalar. 10 dakikada 3 başarısız giriş = 2 saat ban. 2. wordpress-xmlrpc: xmlrpc.php'ye yapılan spam ve DDoS denemelerini yakalar. 5 dakikada 2 istek = 24 saat ban (çünkü xmlrpc genelde botlar kullanır).
logpath kısmını kendi sunucunuza göre ayarlayın. Apache kullanıyorsanız /var/log/apache2/access.log olabilir. Ben Nginx tercih ediyorum, çünkü yüksek trafikte daha performanslı. diolivo.com.tr'de 6 ayda %340 trafik artışı yaşadık, Nginx olmasaydı sunucu çökebilirdi.
Logpath Nasıl Bulunur
Eğer log dosyanızın yerini bilmiyorsanız:
sudo nginx -V 2>&1 | grep "access-log"
# veya
sudo find /var/log -name "*access.log"
WordPress için önemli: Eğer Cloudflare kullanıyorsanız, Nginx loglarında gerçek IP yerine Cloudflare IP'leri görünür. Bunu düzeltmek için ngx_http_realip_module aktif olmalı ve nginx.conf'a şunu ekleyin:
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
# (diğer Cloudflare IP blokları)
real_ip_header CF-Connecting-IP;
Ben futia.io'da bunu yapmazsam, fail2ban Cloudflare'in IP'sini banlar ve tüm site çöker. O yüzden ilk kurulumda mutlaka test edin.
Filter Dosyaları: Regex Pattern'leri ile Log Tarama
fail2ban, log dosyalarını okumak için regex kullanır. Filter dosyaları /etc/fail2ban/filter.d/ klasöründe bulunur. WordPress için iki custom filter oluşturacağız.
wordpress-auth.conf
/etc/fail2ban/filter.d/wordpress-auth.conf dosyasını oluşturun:
[Definition]
failregex = ^<HOST> .* "POST /wp-login\.php HTTP.*" 200
^<HOST> .* "POST /wp-admin/admin-ajax\.php HTTP.*" 200
^<HOST> .* "POST /xmlrpc\.php HTTP.*" 200
ignoreregex =
Bu regex, Nginx access.log'unda şu formatı arar:
192.168.1.50 - - [15/May/2024:14:32:10 +0000] "POST /wp-login.php HTTP/1.1" 200 1234 "-" "Mozilla/5.0"
<HOST> kısmı fail2ban'in özel değişkeni, IP adresini otomatik yakalar. 200 status kodu önemli, çünkü başarısız giriş denemesi bile 200 döner (WordPress'in kötü tasarımı). Eğer 401 veya 403 dönseydi daha kolay yakalardık.
wordpress-xmlrpc.conf
/etc/fail2ban/filter.d/wordpress-xmlrpc.conf dosyasını oluşturun:
[Definition]
failregex = ^<HOST> .* "POST /xmlrpc\.php HTTP.*"
ignoreregex =
xmlrpc.php, WordPress'in eski API sistemi. Pingback spam, brute force ve DDoS için çok kullanılır. Ben müşterilere "xmlrpc'yi tamamen kapat" diyorum, ama bazıları mobil uygulama için kullanıyor. O yüzden kapatamıyorsanız fail2ban ile sıkı koruyun.
Filter Test Etme
Filter'ınızın çalışıp çalışmadığını test etmek için fail2ban-regex kullanın:
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/wordpress-auth.conf
Çıktıda "Success" ve yakalanan satır sayısını göreceksiniz. Eğer 0 match görüyorsanız, regex yanlış veya log formatı farklı. Ben her yeni filter yazdığımda mutlaka test ederim, yokusunda production'da "neden ban olmuyor" diye 2 saat hata ararım.
fail2ban Servisini Yeniden Başlatma ve Durum Kontrolü
Yeni jail ve filter ekledikten sonra servisi yeniden başlatın:
sudo systemctl restart fail2ban
sudo systemctl status fail2ban
Eğer hata varsa, log dosyasına bakın:
sudo tail -f /var/log/fail2ban.log
Sık karşılaşılan hatalar:
- "No file(s) found for glob": logpath yanlış veya dosya yok
- "Unable to find a corresponding IP address": regex IP'yi yakalayamıyor,
<HOST>yerleştirmesini kontrol edin - "Already running": Servis zaten çalışıyor,
sudo systemctl stop fail2banyapıp tekrar başlatın
Aktif jail'leri görmek için:
sudo fail2ban-client status
Çıktı:
Status
|- Number of jail: 2
`- Jail list: wordpress-auth, wordpress-xmlrpc
Belirli bir jail'in detayını görmek için:
sudo fail2ban-client status wordpress-auth
Çıktıda "Currently banned" kısmında banlı IP'leri göreceksiniz. Ben bunu günde 1 kez kontrol ederim, meşru kullanıcı yanlışlıkla banlanmış mı diye.
Manuel Test: Kendi IP'nizi Banlayıp Kaldırma
Kurulumun çalıştığından emin olmak için kendi IP'nizi kasıtlı olarak banlayın. UYARI: Bunu yapmadan önce SSH bağlantınızın kapanmayacağından emin olun, yoksa sunucuya erişiminizi kaybedersiniz.
1. Mevcut IP'nizi öğrenin:
curl ifconfig.me
2. WordPress login sayfasına 3 kez yanlış şifre girin (tarayıcıdan veya curl ile):
curl -X POST https://siteniz.com/wp-login.php \
-d "log=admin&pwd=yanlis_sifre&wp-submit=Log+In"
Bunu 3 kez tekrarlayın. Ardından fail2ban logunu kontrol edin:
sudo tail -f /var/log/fail2ban.log
Şöyle bir satır görmelisiniz:
2024-05-15 14:35:22,341 fail2ban.actions [12345]: NOTICE [wordpress-auth] Ban 192.168.1.50
3. IP'nizi manuel kaldırmak için:
sudo fail2ban-client set wordpress-auth unbanip 192.168.1.50
Veya tüm banlı IP'leri temizlemek için:
sudo fail2ban-client unban --all
Ben test ortamında bunu sık yaparım, ama production'da dikkatli olun. Eğer yanlışlıkla kendi ofis IP'nizi banlarsanız ve SSH erişiminiz yoksa, sunucu sağlayıcınızın konsolundan giriş yapmanız gerekir.
Gerçek Vaka: memuratamalari.com'da Günlük 3.200 Brute Force Denemesi
memuratamalari.com, kamu personel ilanlarını otomatik yayınlayan bir site. ilan.gov.tr API'sinden günde 50+ ilan çekiyoruz, 40.400 aylık organik arama var. Geçen yıl siteyi yeni sunucuya taşıdıktan 2 gün sonra CPU kullanımı %90'a çıktı. Logları inceledim, günde 3.200'den fazla wp-login.php isteği vardı, hepsi farklı IP'lerden.
İlk denemede Wordfence kullandım, ama ücretsiz sürümü rate limiting yapamıyor, sadece bildirim gönderiyor. Premium $119/yıl, müşteri "sunucu seviyesinde çöz" dedi. fail2ban'i kurdum, şu ayarları kullandım:
maxretry=2(çok agresif, ama botlar 2'den fazla denemez)bantime=14400(4 saat, uzun ama etkili)findtime=300(5 dakika, kısa pencere)
3 gün içinde 847 IP banlandı. CPU kullanımı %15'e düştü, sayfa yükleme süresi 2.1 saniyeden 0.8 saniyeye indi. Müşteri "sitenin hızlandığını fark ettik" dedi, ben de "evet, çünkü artık botlara kaynak harcamıyoruz" dedim.
Ek olarak xmlrpc.php'yi tamamen kapattım (WordPress ayarlarından), çünkü site mobil uygulama kullanmıyordu. Eğer siz kullanıyorsanız, fail2ban ile korumanız yeterli.
İleri Seviye: E-posta Bildirimleri ve Slack Entegrasyonu
fail2ban, IP banladığında e-posta gönderebilir. jail.local'de action = %(action_mwl)s satırı bunu aktif eder. mwl = "mail with log", yani log satırlarıyla birlikte mail gönder.
E-posta ayarları için /etc/fail2ban/jail.local'de:
[DEFAULT]
destemail = info@futia.net
sender = fail2ban@futia.io
mta = sendmail
sendmail yerine mail veya postfix de kullanabilirsiniz. Ben genelde Postfix kuruyorum, çünkü daha güvenilir. Ama e-posta yerine Slack bildirimi tercih ediyorum, daha hızlı görüyorum.
Slack entegrasyonu için custom action oluşturun. /etc/fail2ban/action.d/slack-notify.conf:
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK/URL \
-H 'Content-Type: application/json' \
-d '{"text":"fail2ban: <ip> banned on <name>"}'
actionunban =
Sonra jail.local'de:
[wordpress-auth]
enabled = true
filter = wordpress-auth
logpath = /var/log/nginx/access.log
maxretry = 3
bantime = 7200
action = %(action_)s
slack-notify[name=wordpress-auth]
Ben bunu futia.io'da kullanıyorum. Her IP banlandığında Slack'te bildirim alıyorum, böylece anormal aktiviteyi hemen fark ediyorum. Örneğin bir gün 40 IP aynı anda banlandı, DDoS saldırısı olduğunu anladım ve Cloudflare'de "Under Attack" modunu aktif ettim.
fail2ban Performansı ve Sunucu Kaynakları
fail2ban Python ile yazılmış, log dosyalarını sürekli okur. Yüksek trafikli sitelerde (günde 1M+ istek) log dosyası çok büyürse fail2ban yavaşlayabilir. Ben şu optimizasyonları yapıyorum:
1. Log rotation: Nginx loglarını günlük rotate edin, böylece dosya boyutu 100MB'ı geçmez. 2. usedns = no: jail.local'de usedns = no ekleyin, DNS lookup yapmaz, daha hızlı. 3. dbfile: fail2ban veritabanını tmpfs'e taşıyın (RAM'de çalışır).
sudo mkdir -p /var/run/fail2ban
sudo chown fail2ban:fail2ban /var/run/fail2ban
Sonra /etc/fail2ban/fail2ban.local:
[Definition]
dbfile = /var/run/fail2ban/fail2ban.sqlite3
Bu sayede disk I/O azalır, özellikle SSD'siz sunucularda fark eder. doktorbul.com'da 79.000 profil sayfası var, günde 200.000+ istek geliyor, fail2ban CPU'nun %0.3'ünü kullanıyor. Yani performans sorunu yaşamıyoruz.
Yaygın Hatalar ve Çözümleri
1. fail2ban IP'leri Banlamıyor
- Filter regex'i yanlış:
fail2ban-regexile test edin - Log dosyası yolu yanlış:
logpathkontrol edin - Servis çalışmıyor:
sudo systemctl status fail2ban
2. Kendi IP'niz Banlandı
Whitelist ekleyin. jail.local'de:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 OFIS_IP_ADRESINIZ
Ben her zaman ofis IP'mi ve Hollanda sunucu IP'lerini whitelist'e eklerim.
3. Cloudflare IP'leri Banlanıyor
Nginx'te real_ip_header CF-Connecting-IP ayarını yapmadıysanız, fail2ban Cloudflare'in IP'sini görür ve banlar. Yukarıdaki "Logpath Nasıl Bulunur" bölümündeki ayarı yapın.
4. fail2ban Başlamıyor
Genelde syntax hatası vardır. Kontrol edin:
sudo fail2ban-client -t
Hata satırını gösterir. Ben genelde virgül veya tırnak unutuyorum, o yüzden her düzenlemeden sonra test ediyorum.
Eğer WordPress siteniz yüksek trafikli veya sürekli bot saldırısı alıyorsa, fail2ban kurmanız 1 saatinizi alır ama aylarca sunucu kaynağı kazandırır. Ben FUTIA'da tüm müşteri sitelerine varsayılan olarak kuruyorum, çünkü sonradan "site yavaş" diye aramalarını istemiyorum. Teknik destek için WhatsApp +90 532 491 17 05 üzerinden ulaşabilir veya info@futia.net adresine yazabilirsiniz. Hollanda'dan çalışıyorum, genelde 2 saat içinde cevap veriyorum.
Sıkça Sorulanlar
fail2ban WordPress için yeterli mi, yoksa Wordfence gibi eklenti de gerekli mi?
fail2ban sunucu seviyesinde çalıştığı için WordPress'ten bağımsız, daha hızlı ve kaynak tüketmez. Wordfence gibi eklentiler PHP seviyesinde çalışır, her istekte devreye girer ve veritabanı sorgusu yapar. Ben ikisini birlikte kullanmayı öneririm: fail2ban brute force için, Wordfence malware taraması ve firewall kuralları için. Ama bütçe kısıtlıysa sadece fail2ban bile %80 koruma sağlar. memuratamalari.com'da sadece fail2ban kullanıyoruz, 40.400 aylık organik aramada hiç sorun yaşamadık.
fail2ban meşru kullanıcıları yanlışlıkla banlayabilir mi?
Evet, eğer maxretry çok düşük ayarlarsanız (örneğin 2) ve kullanıcı şifresini unutmuşsa banlanabilir. Ben genelde maxretry=3 kullanırım, 3 yanlış deneme normal kullanıcı için makul. Ayrıca ignoreip parametresiyle ofis IP'nizi veya güvendiğiniz IP bloklarını whitelist'e ekleyin. Eğer yanlışlıkla banlama olursa, kullanıcı 'sudo fail2ban-client set wordpress-auth unbanip IP_ADRESI' komutuyla hemen kaldırabilir. Ben müşterilere 'bantime=3600' (1 saat) öneriyorum, çok uzun değil ama botları caydırır.
fail2ban Cloudflare arkasında çalışan WordPress'te nasıl kullanılır?
Cloudflare kullanıyorsanız, Nginx loglarında gerçek IP yerine Cloudflare IP'leri görünür. Bunu düzeltmek için Nginx'te ngx_http_realip_module aktif olmalı ve nginx.conf'a 'set_real_ip_from' direktifleriyle Cloudflare IP blokları eklenmeli. Ayrıca 'real_ip_header CF-Connecting-IP;' satırını ekleyin. Bunu yapmazsanız fail2ban Cloudflare'in IP'sini banlar ve tüm siteniz çöker. Ben futia.io'da bu hatayı bir kez yaptım, 10 dakika site down kaldı. O günden beri her kurulumda ilk adım olarak real_ip ayarını yapıyorum.
fail2ban jail ve filter dosyalarını test etmenin en hızlı yolu nedir?
fail2ban-regex komutu en hızlı test yöntemi. Örnek: 'sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/wordpress-auth.conf' komutu, filter'ınızın kaç log satırını yakaladığını gösterir. Eğer 0 match görüyorsanız, regex yanlış veya log formatı farklı. Ayrıca 'sudo fail2ban-client -t' komutu syntax hatalarını kontrol eder. Ben her yeni filter yazdığımda mutlaka bu iki komutu çalıştırırım, yoksa production'da 'neden ban olmuyor' diye saatlerce hata ararım. Test ortamında kendi IP'nizi kasıtlı banlayıp kaldırmak da iyi pratik.
fail2ban ile xmlrpc.php saldırıları nasıl engellenir?
xmlrpc.php WordPress'in eski API sistemi, pingback spam ve brute force için çok kullanılır. fail2ban ile engellemek için özel bir jail oluşturun: maxretry=2, bantime=86400 (24 saat), findtime=300 (5 dakika). Filter dosyasında 'POST /xmlrpc\.php' pattern'ini arayın. Ama en iyi çözüm xmlrpc'yi tamamen kapatmak, eğer mobil uygulama kullanmıyorsanız. WordPress ayarlarından veya .htaccess'te 'deny from all' kuralıyla kapatabilirsiniz. Ben memuratamalari.com'da xmlrpc'yi kapattım, günlük 800+ spam denemesi sıfıra indi. Eğer kapatamıyorsanız fail2ban yeterli koruma sağlar.
Bu yazıdaki tekniklerden birini uygulamak ister misiniz? Kısa bir form doldurun, 48 saat içinde ücretsiz ön inceleme raporu mailinize düşsün.