WordPress siteniz her gün binlerce başarısız giriş denemesiyle bombardımana tutuluyorsa, yalnız değilsiniz. Bu durum internete açık her WordPress kurulumunun kaçınılmaz gerçeği. Botlar /wp-login.php adresinizi bulduğu an, sistematik şifre denemeleri başlıyor ve bu hem sunucu kaynaklarınızı tüketiyor hem de gerçek bir tehdit oluşturuyor. fail2ban bu soruna zarif ve güçlü bir çözüm sunuyor: saldırganları kaynaklarda yakalayıp otomatik olarak yasaklıyor.
fail2ban Nedir ve Neden WordPress için Mükemmel?
fail2ban, log dosyalarını izleyerek belirli kalıplara uyan IP adreslerini tespit eden ve bunları firewall kurallarıyla engelleyen bir intrusion prevention aracı. Python ile yazılmış, daemon olarak çalışıyor ve temel mantığı son derece basit: çok fazla başarısız deneme yaptıysan, bir süreliğine dışarıda kalırsın.
WordPress brute force saldırıları için bu araç özellikle etkili çünkü:
- WordPress giriş hataları log dosyalarına yazılabiliyor
/wp-login.phpve/xmlrpc.phpüzerindeki saldırılar pattern olarak kolayca tanımlanabiliyor- fail2ban hem Nginx hem Apache ile kusursuz entegre çalışıyor
- Gerçek kullanıcıları etkilemeden saldırganları bloke edebiliyorsunuz
Ortam Gereksinimleri ve Hazırlık
Bu rehberde Ubuntu/Debian tabanlı bir sistem ve Nginx web sunucusu kullanıyoruz. Apache kullananlar için farklı olan noktaları ayrıca belirteceğim.
Başlamadan önce mevcut durumu kontrol edelim:
# fail2ban kurulu mu kontrol et
systemctl status fail2ban
# Nginx log dizinini kontrol et
ls -la /var/log/nginx/
# WordPress access loglarının nerede tutulduğunu bul
grep -r "access_log" /etc/nginx/sites-enabled/
Eğer fail2ban kurulu değilse:
# Debian/Ubuntu
sudo apt update && sudo apt install -y fail2ban
# RHEL/CentOS/AlmaLinux
sudo dnf install -y epel-release
sudo dnf install -y fail2ban
# Servisi başlat ve enable et
sudo systemctl enable --now fail2ban
WordPress Log Yapısını Anlamak
fail2ban’ın çalışması için WordPress’in başarısız giriş denemelerini bir yere yazması gerekiyor. Burada birkaç farklı yaklaşım var.
Yaklaşım 1: Nginx Access Log Üzerinden
Bu en yaygın ve en az konfigürasyon gerektiren yöntem. Nginx’in access logunu izleyerek /wp-login.php‘ye yapılan POST isteklerini ve dönen HTTP kodlarını analiz ediyoruz.
Nginx site konfigürasyonunuzda WordPress giriş sayfası için özel log formatı tanımlayabilirsiniz:
# /etc/nginx/sites-available/wordpress.conf içinde
log_format wp_login '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
server {
listen 80;
server_name siteniz.com;
# WordPress login için ayrı log
location = /wp-login.php {
access_log /var/log/nginx/wordpress-login.log wp_login;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# XMLRPC brute force için de engelle
location = /xmlrpc.php {
access_log /var/log/nginx/wordpress-login.log wp_login;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
# Nginx konfigürasyonunu test et ve yeniden yükle
sudo nginx -t && sudo systemctl reload nginx
Yaklaşım 2: WordPress Auth Log Plugin ile
Daha granüler kontrol için WordPress tarafında da loglama yapabilirsiniz. WP Fail2Ban gibi bir plugin, başarısız giriş denemelerini syslog’a yazıyor ve fail2ban bu logları okuyabiliyor. Bu yöntemi ilerleyen bölümde ele alacağız.
fail2ban Filter Oluşturma
fail2ban için özel bir WordPress filtresi oluşturmamız gerekiyor. Bu filtre, log satırlarından saldırgan IP adreslerini ayıklayacak.
Nginx Access Log için Filter
sudo nano /etc/fail2ban/filter.d/wordpress-nginx.conf
[Definition]
# Başarısız WordPress login denemelerini yakala
# HTTP 200 dönen ama yanlış şifre girilen durumları da yakala
failregex = ^<HOST> .* "POST /wp-login.php HTTP.*" (200|403|429) .*$
^<HOST> .* "POST /xmlrpc.php HTTP.*" (200|403) .*$
^<HOST> .* "GET /wp-login.php?action=register HTTP.*" .*$
ignoreregex = ^<HOST> .* "GET /wp-login.php HTTP.*" 200 .*$
Burada dikkat edilmesi gereken nokta: WordPress başarısız girişlerde genellikle HTTP 200 dönüyor çünkü hata sayfasını HTML olarak sunuyor. Bu yüzden sadece status code’a bakamıyoruz. Bunun için iki seçeneğimiz var: ya WordPress’e başarısız girişlerde 403 döndürtüyoruz ya da daha akıllı bir yaklaşım benimsiyoruz.
Daha Akıllı Filter: Login Hata Mesajları ile
Nginx’e WordPress’ten gelen yanıtın içeriğine göre karar vermesini söyleyemeyiz doğrudan, ama şöyle bir yaklaşım işe yarıyor: aynı IP’den kısa sürede çok sayıda POST geliyorsa bu brute force’tur.
sudo nano /etc/fail2ban/filter.d/wordpress-brute.conf
[INCLUDES]
before = common.conf
[Definition]
_daemon = wordpress
# WP Fail2Ban plugin kullanıyorsanız
failregex = ^%(__prefix_line)sAuthentication failure for .* from <HOST>$
^%(__prefix_line)sBlocked authentication attempt for .* from <HOST>$
^%(__prefix_line)sXMLRPC authentication failure from <HOST>$
# Nginx log formatı için
# POST isteklerini say - aynı IP'den çok fazla POST = brute force
alt_failregex = ^<HOST> .* "POST /wp-login.php
ignoreregex =
fail2ban Jail Konfigürasyonu
Filter hazır, şimdi jail (cezaev) tanımlamamız gerekiyor. Jail, filtrenin hangi log dosyasına uygulanacağını, kaç başarısız deneme sonrası ban yeneceğini ve ban süresini belirliyor.
Önemli kural: Asla /etc/fail2ban/jail.conf dosyasını doğrudan düzenleme. Paket güncellemelerinde bu dosya sıfırlanabilir. Bunun yerine /etc/fail2ban/jail.local kullan.
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
# Varsayılan ban süresi: 1 saat
bantime = 3600
# 10 dakika içindeki denemeleri say
findtime = 600
# Maksimum başarısız deneme sayısı
maxretry = 5
# Kendi IP'ni asla banlama - VPN/ofis IP'lerini ekle
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 192.168.0.0/16
# Backend seçimi - systemd varsa onu kullan
backend = auto
# Email bildirimi (opsiyonel, SMTP ayarlıysa)
# destemail = [email protected]
# sender = [email protected]
# action = %(action_mwl)s
# ============================================
# WordPress Brute Force Koruması
# ============================================
[wordpress-nginx]
enabled = true
filter = wordpress-nginx
port = http,https
logpath = /var/log/nginx/wordpress-login.log
maxretry = 3
findtime = 300
bantime = 7200
action = iptables-multiport[name=wordpress, port="http,https", protocol=tcp]
[wordpress-xmlrpc]
enabled = true
filter = wordpress-nginx
port = http,https
logpath = /var/log/nginx/wordpress-login.log
maxretry = 2
findtime = 60
bantime = 86400
# SSH koruması da açık olsun (genellikle varsayılan gelir ama kontrol et)
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 4
bantime = 3600
Konfigürasyonu uygulamak için:
# Syntax kontrolü
sudo fail2ban-client -t
# fail2ban'ı yeniden başlat
sudo systemctl restart fail2ban
# Jail listesini kontrol et
sudo fail2ban-client status
WP Fail2Ban Plugin ile Gelişmiş Entegrasyon
Nginx log analizi iyi çalışıyor, ancak WP Fail2Ban plugin ile çok daha detaylı bilgi elde edebilirsiniz. Bu plugin, başarısız girişleri, spam yorumları, kullanıcı adı sorgularını ve daha fazlasını syslog’a yazıyor.
Plugin’i kurup aktive ettikten sonra /etc/rsyslog.d/ altında bir konfigürasyon oluşturun:
sudo nano /etc/rsyslog.d/wordpress.conf
# WordPress loglarını ayrı dosyaya yönlendir
if $programname == 'wordpress' then /var/log/wordpress.log
& stop
sudo systemctl restart rsyslog
Ardından fail2ban jail’ini güncelleyin:
[wordpress-hard]
enabled = true
filter = wordpress-hard
logpath = /var/log/wordpress.log
maxretry = 1
bantime = 604800
findtime = 3600
port = http,https
[wordpress-soft]
enabled = true
filter = wordpress-soft
logpath = /var/log/wordpress.log
maxretry = 5
bantime = 3600
findtime = 600
port = http,https
WP Fail2Ban plugin’i ile gelen hazır filter dosyaları genellikle /usr/share/doc/wp-fail2ban/ altında bulunuyor. Bunları kopyalayabilirsiniz:
# WP Fail2Ban filter'larını fail2ban dizinine kopyala
sudo cp /usr/share/doc/wp-fail2ban/filters.d/wordpress-hard.conf /etc/fail2ban/filter.d/
sudo cp /usr/share/doc/wp-fail2ban/filters.d/wordpress-soft.conf /etc/fail2ban/filter.d/
sudo systemctl reload fail2ban
Gerçek Dünya Senaryoları ve İnce Ayarlar
Senaryo 1: Distributed Brute Force Saldırısı
Tek bir IP değil, botnet üzerinden dağıtılmış saldırılar geliyor. Bu durumda maxretry değerini düşürün ama ignoreip listenizi kontrol edin. Ayrıca rate limiting ekleyin:
# Nginx'te rate limiting - wp-login.php için
limit_req_zone $binary_remote_addr zone=wp_login:10m rate=1r/s;
server {
location = /wp-login.php {
limit_req zone=wp_login burst=3 nodelay;
limit_req_status 429;
# 429 döndüğünde fail2ban loglar
access_log /var/log/nginx/wordpress-login.log wp_login;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Bu durumda filter’ınızı 429 kodunu da kapsayacak şekilde güncelleyin (zaten önceki örnekte mevcut).
Senaryo 2: Repeat Offender Yönetimi
Aynı IP tekrar tekrar geliyorsa ban süresini artırmalısınız. fail2ban’ın recidive jail’i tam bunun için:
[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
action = iptables-allports[name=recidive]
bantime = 604800
findtime = 86400
maxretry = 3
Bu jail, fail2ban’ın kendi logunu izliyor. Bir IP 24 saat içinde 3 kez banlandıysa, 1 haftalık bana çekiyor. Gerçekten ısrarcı saldırganlar için mükemmel.
Senaryo 3: Coğrafi Engelleme ile Birlikte Kullanım
fail2ban tek başına da güçlü ama GeoIP tabanlı engelleme ile birleştirince çok daha etkili. Türkiye’de yayın yapan bir site için Türkiye dışından gelen login denemelerini direk engelleyebilirsiniz. Bu Nginx seviyesinde yapılıyor, fail2ban ise kaçananları yakalıyor.
fail2ban Monitoring ve Yönetim
Sistemi kurup bırakmak olmaz. Düzenli takip şart.
Mevcut Durumu Kontrol Et
# Tüm aktif jail'leri listele
sudo fail2ban-client status
# Spesifik jail durumu
sudo fail2ban-client status wordpress-nginx
# Bir IP'nin banını kaldır (yanlışlıkla banlandıysa)
sudo fail2ban-client set wordpress-nginx unbanip 1.2.3.4
# Banlı IP listesini görüntüle
sudo fail2ban-client status wordpress-nginx | grep "Banned IP"
# iptables kurallarını kontrol et
sudo iptables -L -n | grep -i fail2ban
Log Analizi
# fail2ban logunu canlı izle
sudo tail -f /var/log/fail2ban.log
# Bugün kaç IP banlandı?
sudo grep "Ban" /var/log/fail2ban.log | grep "$(date +%Y-%m-%d)" | wc -l
# En çok saldıran IP'leri bul
sudo grep "Ban" /var/log/fail2ban.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head -20
# WordPress login logunu analiz et
sudo awk '{print $1}' /var/log/nginx/wordpress-login.log | sort | uniq -c | sort -rn | head -10
Filter Test Etme
Yeni bir filter yazdınızda test etmeden uygulamaya almayın:
# Filter'ı log dosyasına karşı test et
sudo fail2ban-regex /var/log/nginx/wordpress-login.log /etc/fail2ban/filter.d/wordpress-nginx.conf
# Verbose çıktı için
sudo fail2ban-regex --print-all-matched /var/log/nginx/wordpress-login.log /etc/fail2ban/filter.d/wordpress-nginx.conf
Bu komut size kaç satırın eşleştiğini gösteriyor. Eğer eşleşme 0 ise filtrenizde sorun var demektir.
Sık Karşılaşılan Sorunlar ve Çözümleri
Sorun: Kendi IP’niz banlandı
Önce paniğe gerek yok. Eğer SSH erişiminiz varsa:
sudo fail2ban-client set wordpress-nginx unbanip SIZIN_IP
# Ardından jail.local'a IP'nizi ignoreip listesine ekleyin
sudo systemctl reload fail2ban
SSH erişiminiz de kesildi ise VPS konsolunu (KVM/VNC) kullanmanız gerekiyor.
Sorun: Filter eşleşmiyor
Log format değişmiş olabilir. Mevcut log satırlarını kontrol edin:
sudo tail -20 /var/log/nginx/wordpress-login.log
Satır formatını görüp regex’inizi buna göre düzenleyin.
Sorun: fail2ban başlamıyor
# Detaylı hata mesajı için
sudo journalctl -xe -u fail2ban
# Konfigürasyon syntax hatası mı var?
sudo fail2ban-client -t
# Log dosyası izinleri
sudo ls -la /var/log/nginx/wordpress-login.log
# fail2ban bu dosyayı okuyabilmeli
sudo chmod 644 /var/log/nginx/wordpress-login.log
Sorun: Çok fazla false positive
maxretry değerini artırın veya findtime penceresini genişletin. Ayrıca meşru kullanıcı IP’lerini ignoreip listesine ekleyin.
Ek Güvenlik Katmanları
fail2ban tek başına yeterli değil, bir parçası. WordPress güvenliği için şunları da ekleyin:
- wp-admin erişimini IP ile kısıtla: Nginx konfigürasyonunda sadece belirli IP’lerden admin erişimine izin verin
- xmlrpc.php’yi tamamen kapat: Jetpack gibi bir plugin kullanmıyorsanız
location = /xmlrpc.php { return 403; }ekleyin - wp-login.php için HTTP Auth ekle: Çift katmanlı koruma için Nginx seviyesinde basic auth uygulayın
- Login URL’yi değiştir: WPS Hide Login gibi plugin ile giriş URL’sini değiştirin, bu botların büyük çoğunluğunu etkisiz kılar
- WordPress güvenlik anahtarlarını düzenli yenile: Compromised session’ları geçersiz kılar
Sonuç
fail2ban ve WordPress entegrasyonu, görece az konfigürasyon çabasıyla çok büyük bir güvenlik kazanımı sağlıyor. Kurduğunuz sistem şunları otomatik yapıyor: log dosyalarını gerçek zamanlı izliyor, şüpheli davranışları tespit ediyor, saldırganları firewall seviyesinde engelliyor ve tekrar eden saldırganları çok daha uzun süreli banlara çekiyor.
Burada anlattığım yaklaşımı kendi ortamınıza uyarlayın. maxretry ve bantime değerlerini sitenizin trafiğine göre ayarlayın, ignoreip listesini güncel tutun ve düzenli olarak logları inceleyin. fail2ban loglarını izlediğinizde sitenize ne kadar saldırı geldiğini görünce şaşıracaksınız.
Son bir not: fail2ban reaktif bir araç, yani saldırı başladıktan sonra devreye giriyor. Nginx rate limiting, login URL gizleme ve iki faktörlü kimlik doğrulama gibi proaktif önlemlerle birleştirince gerçekten sağlam bir savunma hattı oluşturuyorsunuz.