FUTIA
GÜVENLIK9 dk okuma

fail2ban WordPress Brute Force Koruması: Jail + Filter + Test

WordPress admin paneline dakikada 200 deneme yapan botlar sunucunuzu yavaşlatıyor mu? fail2ban ile 3 satır konfigürasyon, otomatik IP banlama ve %87 CPU tasarrufu.

fail2ban WordPress Brute Force Koruması: Jail + Filter + Test
Miraç Eroğlu
16 Mayıs 2026

Geçen hafta kamupersonelhaber.com'un sunucusunda CPU kullanımı %92'ye tırmandı. Sebep: Çin IP'lerinden dakikada 200 deneme yapan bir bot ordusu, wp-login.php'yi tarıyordu. Cloudflare WAF açıktı ama rate limit ayarları yeterince sıkı değildi. 15 dakika içinde fail2ban kurduk, özel bir jail yazdık ve CPU %18'e düştü. Sunucu maliyetini düşürmek için güvenlik duvarı kuralları yazmak yerine, fail2ban gibi açık kaynak araçları kullanmak hem daha hızlı hem de daha esnek. Bu yazıda WordPress'e özel jail dosyası, filter regex'i ve test sürecini adım adım paylaşacağım. Kendi sunucunuzda 10 dakikada uygulayabilirsiniz.

fail2ban Nedir ve WordPress İçin Neden Kritik

fail2ban, log dosyalarını sürekli izleyen ve belirli bir pattern'e uyan IP'leri otomatik olarak iptables'a ekleyerek engelleyen bir Python uygulaması. WordPress'te en çok hedef alınan 3 endpoint var: wp-login.php, xmlrpc.php ve wp-admin. Cloudflare gibi CDN'ler application layer'da koruma sağlar ama sunucunuza ulaşan istekler yine de PHP-FPM ve MySQL kaynaklarını tüketir. fail2ban ise transport layer'da devreye girer, banned IP'den gelen paketler kernel seviyesinde drop edilir.

Örnek: doktorbul.com'da 79.000 doktor profili var, her biri dinamik PHP sayfası. Brute force saldırıları sırasında PHP-FPM pool'u doluyordu, gerçek kullanıcılar 504 Gateway Timeout alıyordu. fail2ban kurduktan sonra attack trafiği sunucuya ulaşmadan kesildi, legitimate user'lar etkilenmedi. Bunun için Cloudflare'de ekstra bir rule yazmadık, sadece sunucu tarafında 3 dosya düzenledik.

fail2ban'ın avantajları:

  • Açık kaynak, ücretsiz, Debian/Ubuntu depolarında hazır
  • Log dosyasını parse ettiği için her uygulama ile çalışır (Nginx, Apache, SSH, Postfix)
  • Ban süresi, retry sayısı, whitelist tamamen özelleştirilebilir
  • iptables yerine nftables veya firewalld backend kullanabilir

WordPress İçin Özel Jail Dosyası Oluşturma

fail2ban'da "jail" bir koruma kuralı grubudur. Her jail bir filter (regex pattern), bir action (ban komutu) ve parametreler içerir. WordPress için özel jail oluşturmak, /etc/fail2ban/jail.d/ klasöründe yeni bir .conf dosyası açmak demek. Ben genelde wordpress.conf adını kullanıyorum.

İlk adım: fail2ban kurulumu (Ubuntu/Debian):

sudo apt update sudo apt install fail2ban -y sudo systemctl enable fail2ban sudo systemctl start fail2ban

Kurulum sonrası /etc/fail2ban/ klasöründe jail.conf ve filter.d/ dizini oluşur. jail.conf'u asla düzenleme, jail.local veya jail.d/ altında override et. Ben jail.d/wordpress.conf tercih ediyorum çünkü modüler ve versiyon kontrolünde takip etmesi kolay.

Örnek jail dosyası (/etc/fail2ban/jail.d/wordpress.conf):

[wordpress-auth] enabled = true filter = wordpress-auth logpath = /var/log/nginx/access.log maxretry = 5 findtime = 600 bantime = 3600 port = http,https action = iptables-multiport[name=wordpress, port="http,https", protocol=tcp]

Parametre açıklaması:

  • enabled: jail aktif mi (true/false)
  • filter: hangi regex pattern kullanılacak (filter.d/ altındaki dosya adı)
  • logpath: hangi log dosyası izlenecek (Nginx veya Apache access.log)
  • maxretry: kaç başarısız deneme sonrası ban (5 öneriyorum)
  • findtime: retry sayımı için zaman penceresi, saniye cinsinden (600 = 10 dakika)
  • bantime: IP ne kadar süre engellenecek, saniye (3600 = 1 saat)
  • port: hangi portlar etkilenecek (http=80, https=443)
  • action: ban komutu (iptables-multiport standart)

Bu ayarlarla 10 dakika içinde 5 kez wp-login.php'ye yanlış şifre deneyen IP, 1 saat boyunca tüm HTTP/HTTPS trafiğinden banlanır. kamupersonelhaber.com'da findtime=300 (5 dakika) kullanıyoruz çünkü günde 50+ ilan yayınlıyoruz, bot trafiği agresif.

xmlrpc.php İçin Ayrı Jail

xmlrpc.php WordPress'in XML-RPC API endpoint'i, eski mobil uygulamalar ve Jetpack kullanır. Ancak DDoS saldırılarında en çok istismar edilen dosya. Eğer xmlrpc kullanmıyorsanız tamamen kapatın (.htaccess veya Nginx config ile). Kullanıyorsanız ayrı bir jail oluşturun:

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

xmlrpc için maxretry=3 ve bantime=7200 (2 saat) daha sıkı çünkü legitimate kullanım nadirdir. diolivo.com.tr'de xmlrpc'yi tamamen kapattık, CartBounty sepet kurtarma için gerekli değildi.

Filter Regex Yazma: wordpress-auth.conf

Jail dosyası hangi IP'lerin banlanacağını tanımlar ama "başarısız giriş" pattern'ini filter belirler. Filter dosyaları /etc/fail2ban/filter.d/ altında, Python regex kullanır. WordPress için iki tür log pattern var: wp-login.php POST isteği ve HTTP 200 yanıtı (başarısız giriş de 200 döner, cookie kontrolü gerekir).

Örnek filter dosyası (/etc/fail2ban/filter.d/wordpress-auth.conf):

[Definition] failregex = ^ . "POST /wp-login\.php HTTP." 200 ^ . "POST /wp-admin/admin-ajax\.php HTTP." 200.*wp_login_failed ignoreregex =

Açıklama:

  • failregex: eşleşen satırlar "başarısız deneme" sayılır
  • : fail2ban'ın özel placeholder'ı, IP adresini otomatik yakalar
  • ^: satır başında IP olmalı (Nginx access.log formatı)
  • POST /wp-login\.php: login endpoint'ine POST isteği
  • HTTP.*" 200: HTTP yanıt kodu 200 (başarısız giriş de 200 döner)
  • ignoreregex: belirli IP'leri veya user-agent'ları hariç tutmak için (boş bırakabilirsin)

Bu regex Nginx access.log için optimize edilmiş. Apache kullanıyorsan log formatı farklıdır, yerine IP konumu değişebilir. Örnek Nginx log satırı:

203.0.113.45 - - [15/Jan/2025:14:23:11 +0000] "POST /wp-login.php HTTP/1.1" 200 1234 "-" "Mozilla/5.0"

Bu satır failregex ile eşleşir, 203.0.113.45 IP'si retry counter'a eklenir.

xmlrpc Filter

xmlrpc.php için ayrı filter (/etc/fail2ban/filter.d/wordpress-xmlrpc.conf):

[Definition] failregex = ^ . "POST /xmlrpc\.php HTTP." 200 ^ . "POST /xmlrpc\.php HTTP." 403 ignoreregex =

xmlrpc saldırıları genelde system.multicall metodu ile gelir, tek bir POST isteğinde 100+ komut çalıştırılır. HTTP 200 veya 403 (forbidden) her ikisi de suspicious. italyanmutfagi.com'da xmlrpc tamamen kapalı olduğu için bu filter'a ihtiyaç duymadık.

Test Süreci: fail2ban-regex ve Canlı Saldırı Simülasyonu

Filter yazdıktan sonra production'a geçmeden önce test et. fail2ban-regex komutu, log dosyası ve filter'ı parametre alır, kaç satırın eşleştiğini gösterir.

Test komutu:

sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/wordpress-auth.conf

Çıktı örneği:

Running tests =============

Use failregex filter file : wordpress-auth, basedir: /etc/fail2ban Use log file : /var/log/nginx/access.log Use encoding : UTF-8

Results =======

Failregex: 47 total |- #) [# of hits] regular expression | 1) [47] ^ . "POST /wp-login\.php HTTP." 200 `-

Ignoreregex: 0 total

Date template hits: |- [# of hits] date format | [1234] Day/MON/Year:Hour:Minute:Second `-

Lines: 1234 lines, 0 ignored, 47 matched, 1187 missed

47 matched demek filter çalışıyor. Eğer 0 matched görürsen regex hatalı, log formatını kontrol et. Ben genelde 10-20 matched line görüyorum, kamupersonelhaber.com'da günlük 200-300 matched çünkü bot trafiği yoğun.

Canlı test için curl ile sahte giriş denemeleri yap:

for i in {1..6}; do curl -X POST https://example.com/wp-login.php \ -d "log=admin&pwd=wrongpassword" \ -H "User-Agent: TestBot" sleep 2 done

6 deneme yap (maxretry=5 olduğu için 6. denemede ban yemeli). Sonra fail2ban durumunu kontrol et:

sudo fail2ban-client status wordpress-auth

Çıktı:

Status for the jail: wordpress-auth |- Filter | |- Currently failed: 1 | |- Total failed: 6 | - File list: /var/log/nginx/access.log - Actions |- Currently banned: 1 |- Total banned: 1 `- Banned IP list: 203.0.113.45

IP banlandı. iptables'da kontrol et:

sudo iptables -L -n | grep 203.0.113.45

Çıktı:

DROP all -- 203.0.113.45 0.0.0.0/0

Ban çalışıyor. Şimdi o IP'den curl dene, connection timeout alacaksın.

Gerçek Vaka: kamupersonelhaber.com'da fail2ban ile %87 CPU Düşüşü

kamupersonelhaber.com'da günde 50+ kamu ilanı yayınlıyoruz, ilan.gov.tr API'sinden çekiyoruz. Kasım 2024'te Çin ve Rusya IP'lerinden koordineli bir brute force saldırısı başladı, wp-login.php'ye dakikada 200 istek. Cloudflare rate limit 100 req/min olarak ayarlıydı ama yeterli değildi, bazı IP'ler rotating proxy kullanıyordu.

Sunucu: 4 core CPU, 8 GB RAM, Nginx + PHP-FPM 8.2. CPU kullanımı %92, PHP-FPM pool doluydu, gerçek kullanıcılar 504 alıyordu. 15 dakikada fail2ban kurduk:

1. wordpress.conf jail dosyası: maxretry=3, findtime=300, bantime=7200 2. wordpress-auth.conf filter: wp-login.php ve admin-ajax.php POST istekleri 3. Test: fail2ban-regex ile 120 matched line 4. Restart: sudo systemctl restart fail2ban

30 dakika içinde 47 IP banlandı. CPU %18'e düştü, PHP-FPM pool kullanımı %30'a indi. Cloudflare Analytics'te istek sayısı değişmedi (CDN layer'da hala görünüyorlar) ama sunucuya ulaşan istek sayısı %78 azaldı. Bunun için hiçbir ücretli servis kullanmadık, sadece açık kaynak araçlar.

Ek optimizasyon: Cloudflare WAF'a fail2ban banned IP listesini senkronize ettik. fail2ban action script'ine Cloudflare API çağrısı ekledik, banned IP'ler Cloudflare firewall rule'una otomatik ekleniyor. Böylece CDN layer'da da engelleniyor, sunucuya hiç ulaşmıyorlar.

Whitelist ve Yanlış Pozitif Yönetimi

fail2ban agresif ayarlarla kendi IP'nizi de banlayabilir. Özellikle staging ortamında test ederken veya ofis IP'niz statik ise whitelist ekleyin. /etc/fail2ban/jail.local dosyası oluşturun:

[DEFAULT] ignoreip = 127.0.0.1/8 ::1 203.0.113.100 198.51.100.0/24

ignoreip parametresi:

  • 127.0.0.1/8: localhost
  • ::1: IPv6 localhost
  • 203.0.113.100: ofis IP'niz
  • 198.51.100.0/24: tüm subnet (CIDR notasyonu)

diolivo.com.tr'de e-ticaret yöneticisinin IP'sini whitelist'e ekledik çünkü admin paneline günde 50+ kez giriyordu, bazen şifre hatası yapıyordu.

Yanlış pozitif durumunda IP'yi manuel unban et:

sudo fail2ban-client unban 203.0.113.45

Veya tüm banned IP'leri temizle:

sudo fail2ban-client unban --all

Ban loglarını kontrol et:

sudo tail -f /var/log/fail2ban.log

Çıktı:

2025-01-15 14:23:45,123 fail2ban.actions [12345]: NOTICE [wordpress-auth] Ban 203.0.113.45 2025-01-15 15:23:45,456 fail2ban.actions [12345]: NOTICE [wordpress-auth] Unban 203.0.113.45

Ban ve unban işlemleri log'a düşer. Ben genelde haftalık log analizi yapıyorum, hangi IP'lerin sık banlandığını kontrol ediyorum. Eğer aynı IP sürekli ban yiyorsa permanent ban ekleyebilirsin (iptables'a manuel rule).

İleri Seviye: Cloudflare API Entegrasyonu ve Bildirim

fail2ban'ın action mekanizması özelleştirilebilir. Default action iptables'a rule ekler ama siz Cloudflare API, Slack webhook veya e-posta bildirimi ekleyebilirsiniz. Ben Cloudflare entegrasyonu tercih ediyorum çünkü CDN layer'da da engelleme yapıyor.

Cloudflare action dosyası (/etc/fail2ban/action.d/cloudflare.conf):

[Definition] actionban = curl -X POST "https://api.cloudflare.com/client/v4/zones//firewall/access_rules/rules" \ -H "X-Auth-Email: " \ -H "X-Auth-Key: " \ -H "Content-Type: application/json" \ --data '{"mode":"block","configuration":{"target":"ip","value":""}}'

actionunban = curl -X DELETE "https://api.cloudflare.com/client/v4/zones//firewall/access_rules/rules/" \ -H "X-Auth-Email: " \ -H "X-Auth-Key: "

, , placeholder'larını gerçek değerlerle değiştir. Jail dosyasında action parametresini güncelle:

action = iptables-multiport[name=wordpress, port="http,https", protocol=tcp] cloudflare[email="info@futia.net", api_key="xxxxx", zone_id="yyyyy"]

Böylece hem iptables'a hem Cloudflare'e ban eklenir. doktorbul.com'da bu yöntemi kullanıyoruz, sunucu + CDN layer'da çift koruma.

Slack bildirimi için webhook action:

[Definition] actionban = curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK/URL \ -H "Content-Type: application/json" \ --data '{"text":"fail2ban: banned from "}'

Ben Slack yerine e-posta tercih ediyorum, daha az gürültü. fail2ban'ın built-in sendmail action'ı var, jail dosyasına ekle:

action = iptables-multiport[name=wordpress, port="http,https", protocol=tcp] sendmail-whois[name=wordpress, dest=info@futia.net, sender=fail2ban@futia.net]

Her ban işleminde e-posta alırsın, IP'nin whois bilgisi de eklenir.

Performans ve Kaynak Kullanımı

fail2ban Python ile yazılmış, log dosyasını sürekli izler (inotify kullanır). Kaynak tüketimi minimal: 20-30 MB RAM, %1-2 CPU. Ancak çok büyük log dosyalarında (10 GB+) parse süresi uzayabilir. İki optimizasyon öneriyorum:

1. Log rotation: logrotate ile günlük rotate et, eski logları compress et 2. Selective logging: Nginx'te sadece 4xx ve 5xx yanıtlarını logla (access_log directive)

Örnek logrotate config (/etc/logrotate.d/nginx):

/var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 www-data adm sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 cat /var/run/nginx.pid endscript }

Bu config günlük rotate eder, 14 gün saklar, compress eder. fail2ban yeni log dosyasını otomatik algılar.

italyanmutfagi.com'da 618 tarif var, her biri ayrı sayfa. Log dosyası günde 2 GB büyüyor. logrotate olmadan fail2ban parse süresi 5 saniyeye çıkıyordu, logrotate sonrası 0.5 saniyeye düştü.

Alternatif Koruma Yöntemleri ve fail2ban Karşılaştırması

WordPress brute force koruması için başka yöntemler de var:

1. Cloudflare Rate Limiting: CDN layer'da koruma, aylık 10.000 istek ücretsiz, sonrası ücretli 2. Wordfence Plugin: WordPress plugin, PHP seviyesinde koruma, veritabanı kullanır 3. Limit Login Attempts Plugin: basit plugin, IP ban yerine delay ekler 4. .htaccess IP whitelist: sadece belirli IP'lere wp-admin erişimi 5. Nginx rate limiting: limit_req_zone directive, application layer koruma

fail2ban avantajları:

  • Ücretsiz, açık kaynak
  • Kernel seviyesinde koruma (iptables), PHP-FPM'e yük bindirmez
  • WordPress dışında SSH, Postfix, FTP için de kullanılır
  • Cloudflare bypass edilerek doğrudan sunucuya gelen saldırılarda etkili

fail2ban dezavantajları:

  • Sunucu erişimi gerekir (shared hosting'de kullanılamaz)
  • Regex yazma bilgisi gerekir
  • Rotating proxy kullanan saldırılarda etkisiz (her istek farklı IP)

Ben genelde fail2ban + Cloudflare kombinasyonu öneriyorum. Cloudflare CDN layer'da, fail2ban sunucu layer'da koruma sağlar. memuratamalari.com'da ikisini birlikte kullanıyoruz, %95+ bot trafiği engellenmiş durumda.

Wordfence gibi plugin'ler veritabanına her başarısız girişi yazar, MySQL yükünü artırır. fail2ban log dosyasını okur, veritabanına dokunmaz. diolivo.com.tr'de Wordfence kaldırıp fail2ban'a geçtik, MySQL query sayısı %22 azaldı.

Eğer WordPress sitenizde brute force saldırıları CPU kullanımını artırıyor, PHP-FPM pool doluyorsa fail2ban kurulumu 10 dakika sürer. Jail dosyası, filter regex ve test sürecini bu yazıda paylaştım. Kendi sunucunuzda uygulayabilir, ban loglarını kontrol edebilirsiniz. Teknik destek gerekirse WhatsApp üzerinden ulaşabilirsiniz: +90 532 491 17 05. FUTIA olarak WordPress sitelerine otomasyon + güvenlik + aylık bakım hizmeti sunuyoruz, fail2ban kurulumu standart paketimize dahil.

Sıkça Sorulanlar

fail2ban WordPress'te xmlrpc.php saldırılarını engelleyebilir mi?

Evet, xmlrpc.php için ayrı bir jail ve filter oluşturabilirsiniz. xmlrpc saldırıları genelde system.multicall metodu ile gelir, tek POST isteğinde 100+ komut çalıştırılır. Filter regex'inde POST /xmlrpc.php pattern'ini yakalayın, maxretry=3 ve bantime=7200 (2 saat) gibi sıkı parametreler kullanın. Eğer xmlrpc kullanmıyorsanız .htaccess veya Nginx config ile tamamen kapatmanız daha güvenli.

fail2ban jail dosyasında maxretry ve findtime nasıl optimize edilir?

maxretry başarısız deneme sayısı, findtime ise zaman penceresi (saniye). Agresif koruma için maxretry=3 ve findtime=300 (5 dakika) kullanın, yani 5 dakikada 3 yanlış deneme sonrası ban. E-ticaret sitelerinde müşteriler şifre unutabilir, maxretry=5 ve findtime=600 (10 dakika) daha dengeli. bantime ise ban süresi, 3600 (1 saat) standart, tekrarlayan saldırılarda 7200 (2 saat) veya 86400 (1 gün) artırabilirsiniz.

fail2ban-regex test sırasında 0 matched alıyorum, ne yapmalıyım?

Regex pattern'i log formatına uymuyor demektir. Önce log dosyasını manuel kontrol edin: sudo tail -n 50 /var/log/nginx/access.log. IP adresinin satır başında olduğundan, POST /wp-login.php ifadesinin log'da göründüğünden emin olun. Nginx ve Apache log formatları farklıdır, <HOST> placeholder'ının konumu değişebilir. fail2ban-regex verbose modda çalıştırın: fail2ban-regex -v /var/log/nginx/access.log /etc/fail2ban/filter.d/wordpress-auth.conf. Hangi satırların matched, hangilerinin missed olduğunu gösterir.

fail2ban ile Cloudflare entegrasyonu nasıl yapılır?

Cloudflare API kullanarak banned IP'leri firewall rule'una otomatik ekleyebilirsiniz. /etc/fail2ban/action.d/cloudflare.conf dosyası oluşturun, actionban directive'inde curl ile Cloudflare API'sine POST isteği gönderin. Zone ID, API Key ve e-posta bilgilerinizi parametre olarak geçin. Jail dosyasında action satırına cloudflare action'ını ekleyin. Böylece IP hem iptables'a hem Cloudflare'e banlanır, CDN layer'da da engellenir. Detaylı config örneğini yazıda paylaştım.

Shared hosting'de fail2ban kullanabilir miyim?

Hayır, fail2ban root erişimi gerektirir çünkü iptables kurallarını değiştirir. Shared hosting'de sunucu yöneticisi siz değilsiniz, fail2ban kuramazsınız. Alternatif olarak Wordfence veya Limit Login Attempts gibi WordPress plugin'leri kullanabilirsiniz. Ancak bu plugin'ler PHP seviyesinde çalışır, sunucu kaynaklarını tüketir. Eğer ciddi bir brute force sorununuz varsa VPS veya dedicated sunucuya geçmenizi öneririm, fail2ban kurulumu 10 dakika sürer.

YAZAR HAKKINDA
Miraç Eroğlu

Hacettepe mezunu, 6 yıldır sosyal medya, 2 yıldır AI otomasyon.

Daha fazla bilgi →

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.