Müsait — Yerel Dijital Ürünler
HCA · Studio
TR — İletişim ↗
Teknik Not 09 · Güvenlik

fail2ban çalışıyor ama kimseyi engellemiyor

Jail aktif, servis sağlıklı, durum çıktısı temiz — ve yasaklanan IP sayısı günlerdir sıfır. WordPress kurulu bir sunucuda bu iyi haber değildir; neredeyse her zaman filtrenin log biçimiyle eşleşmediği anlamına gelir.

Sunucu
OpenLiteSpeed
Belirti
Total banned: 0
Kanıt
fail2ban-regex
Kısa cevap

Hazır WordPress filtreleri Apache'nin birleşik log biçimini varsayar ve satırın IP ile başladığını kabul eder. OpenLiteSpeed'de log biçimi vhost bazında değişir; birçok kurulumda satır vhost adıyla başlar ("alanadi.com 1.2.3.4 - - [..."), bazılarında doğrudan IP ile. Satır başını ^<HOST> diye sabitleyen bir desen bu durumda hiçbir şeyle eşleşmez — ve fail2ban eşleşme bulamadığında hata vermez, sadece kimseyi engellemez. Çözüm, isteğe bağlı bir ön alan kabul eden desen yazmak ve fail2ban-regex ile gerçek log dosyası üzerinde test etmektir.

Belirti

Kurulum yapılmış, jail tanımlanmış, servis çalışıyor. Durumu sorarsınız:

fail2ban-client status wordpress-ols

Çıktı sağlıklı görünür: jail aktif, dosya izleniyor, hata yok. Ama iki satır dikkat çeker: Currently failed: 0 ve Total banned: 0.

İnternete açık, WordPress kurulu bir sitede wp-login.php ve xmlrpc.php denemeleri kesintisiz gelir. Bu sayıların günlerce sıfır kalması, saldırı olmadığı anlamına gelmez; filtrenin log satırlarını okuyamadığı anlamına gelir.

Log biçimi farkı

Hazır apache-* ve topluluk WordPress filtreleri, satırın doğrudan istemci IP'siyle başladığını varsayar:

1.2.3.4 - - [18/Sep/2026:07:14:22 +0000] "POST /wp-login.php HTTP/2" 200 1234

OpenLiteSpeed'de log biçimi vhost yapılandırmasındaki logFormat satırına bağlıdır ve panel kurulumlarında çoğu zaman vhost adı öne eklenir:

"alanadi.com 1.2.3.4 - - [18/Sep/2026:07:14:22 +0000] "POST /wp-login.php HTTP/2" 200 1234"

Aradaki fark tek bir alandır, ama ^<HOST> ile başlayan bir desen için yıkıcıdır: satırın başında IP yoktur, dolayısıyla hiçbir eşleşme olmaz.

Daha can sıkıcısı, aynı yöneticinin iki sunucusunda iki farklı biçim olabilmesidir. Bir sunucuda çalışan filtreyi diğerine kopyaladığınızda sessizce ölür. Bu yüzden filtreyi varsayıma değil, o sunucudaki gerçek satıra göre yazmak gerekir.

Dayanıklı filtre

Her iki biçimi de karşılayan yaklaşım, satır başında isteğe bağlı bir alan kabul etmektir. /etc/fail2ban/filter.d/wordpress-ols.conf:

[Definition]
failregex = ^"?(?:\S+ )?<HOST> - -.*"(?:GET|POST|HEAD) [^"]*(?:wp-login\.php|xmlrpc\.php)
ignoreregex =
datepattern = %%d/%%b/%%Y:%%H:%%M:%%S %%z

Desenin parçaları:

  • ^"? — bazı biçimler satırı tırnakla sarar, isteğe bağlı kabul edilir
  • (?:\S+ )? — varsa vhost alanını yutar, yoksa sorun çıkarmaz
  • <HOST> — fail2ban'ın IP yakaladığı özel yer tutucu
  • wp-login\.php|xmlrpc\.php — kaba kuvvetin iki klasik hedefi
  • %%d/%%b/… — yüzdeler bilerek çift: fail2ban yapılandırmada tek % işaretini değişken sanır ve filtreyi hiç yüklemez. Satırı tümden çıkarırsanız fail2ban tarihi kendisi tanır.

Hem GET hem POST yakalanır; saldırganlar giriş sayfasını önce GET ile yoklar.

Testsiz kural yazmayın

Bu notun en önemli cümlesi budur: filtreyi gerçek log dosyanızda test etmeden devreye almayın. fail2ban bunun için hazır bir araç sunar:

fail2ban-regex /home/alanadi.com/logs/alanadi.com.access_log \
               /etc/fail2ban/filter.d/wordpress-ols.conf

Çıktıdaki iki satıra bakın:

Lines: 128934 lines, 0 ignored, 36925 matched, 92009 missed

matched sıfırsa deseniniz çalışmıyordur — jail'i kurmanın anlamı yok. Binlerce eşleşme görüyorsanız hem desen doğrudur hem de sitenizin ne kadar saldırı aldığını öğrenmiş olursunuz.

Not: missed sayısının yüksek olması normaldir; o satırlar sıradan trafiktir.

Jail yapılandırması

/etc/fail2ban/jail.local içine:

[wordpress-ols]
enabled  = true
port     = http,https
filter   = wordpress-ols
logpath  = /home/*/logs/*.access_log
maxretry = 5
findtime = 600
bantime  = 3600
ignoreip = 127.0.0.1/8 ::1

logpath joker karakter kabul eder; çok siteli sunucularda her vhost'u tek tek yazmak yerine kalıp kullanın. Yeni site eklendiğinde otomatik kapsanır.

Devreye aldıktan sonra yeniden yükleyin ve gerçekten iş gördüğünü doğrulayın:

fail2ban-client reload
fail2ban-client status wordpress-ols

Birkaç saat içinde Total banned sayısının artmaya başlaması gerekir. Hâlâ sıfırsa ya filtre eşleşmiyordur ya da log akmıyordur — ikincisi için log dizini izinlerini kontrol edin.

Cloudflare tuzağı

Site bir CDN arkasındaysa sunucuya ulaşan bağlantı ziyaretçiden değil, CDN düğümünden gelir. Log'a yazılan IP de CDN'in IP'sidir. Bu durumda fail2ban gerçek saldırganı değil, CDN'i engeller — ve tek bir yasaklama tüm ziyaretçileri dışarıda bırakabilir.

İki önlem birlikte alınmalıdır. Önce CDN aralıklarını yasaklama dışına çıkarın:

ignoreip = 127.0.0.1/8 ::1 173.245.48.0/20 103.21.244.0/22 ...

Ardından gerçek ziyaretçi IP'sinin log'a yazılmasını sağlayın; CDN bunu bir başlıkta taşır ve web sunucusu bu başlığı istemci IP'si olarak kabul edecek şekilde yapılandırılmalıdır. OpenLiteSpeed'de bu, orijinal IP başlığını kullan seçeneğidir. Aksi hâlde hem engelleme yanlış hedefe gider hem de istatistikleriniz anlamsız olur.

Özet

fail2ban'ın en tehlikeli tarafı, yanlış yapılandırıldığında çalışıyormuş gibi görünmesidir. Servis ayakta, jail aktif, hata yok — ama koruma sıfır. Bu yüzden kurulumun son adımı "servisi başlattım" değil, "fail2ban-regex gerçek log'umda eşleşme buluyor ve yasaklama sayacı artıyor" olmalıdır. Koruma, doğrulanana kadar varsayımdır.

Hızlı referans
Belirti
Jail aktif, Total banned: 0, hata yok
Kök neden
OLS log satırı vhost adıyla başlar; ^<HOST> eşleşmez
Dayanıklı desen
^"?(?:\S+ )?<HOST> - - ile her iki biçim karşılanır
Zorunlu adım
fail2ban-regex log filtre ile test — matched sıfırsa kural ölüdür
Hedefler
wp-login.php ve xmlrpc.php, GET ve POST birlikte
Çok siteli
logpath = /home/*/logs/*.access_log joker kullanın
CDN arkası
CDN aralıkları ignoreip'te olmalı, yoksa CDN'i engellersiniz
Ön koşul
Log akmıyorsa fail2ban körelir — önce log iznini doğrulayın
Sık Sorulan Sorular

fail2ban ve OpenLiteSpeed hakkında.

Jail aktif görünüyor ama hiç yasaklama yok. Sorun ne?

Neredeyse her zaman filtre deseni log biçimiyle eşleşmiyordur. OpenLiteSpeed loglarında satır çoğu kurulumda vhost adıyla başlar, hazır WordPress filtreleri ise satırın IP ile başladığını varsayar. fail2ban eşleşme bulamadığında hata üretmez, sadece kimseyi engellemez. fail2ban-regex ile test edin; matched sayısı sıfırsa sebebi budur.

Filtremi nasıl doğru test ederim?

fail2ban-regex komutunu gerçek erişim kaydınız ve filtre dosyanızla çalıştırın. Çıktıdaki matched sayısına bakın. Sıfırsa desen çalışmıyordur. Yüksek bir sayı görüyorsanız hem desen doğrudur hem de sitenizin aldığı kaba kuvvet trafiğinin gerçek ölçüsünü öğrenmiş olursunuz.

Sitem Cloudflare arkasında, fail2ban yine de işe yarar mı?

Ek yapılandırma olmadan yarardan çok zarar verir. Loglara CDN'in IP'si yazılır, dolayısıyla fail2ban saldırganı değil CDN'i engeller ve tek bir yasaklama bütün ziyaretçileri dışarıda bırakabilir. CDN aralıklarını ignoreip listesine ekleyin ve web sunucusunu gerçek ziyaretçi IP'sini loglayacak şekilde yapılandırın.

fail2ban yerine WordPress güvenlik eklentisi yeterli olmaz mı?

Farklı katmanlarda çalışırlar. Eklenti isteği ancak PHP çalıştıktan sonra görür; yani her deneme yine sunucu kaynağı tüketir. fail2ban ise IP'yi güvenlik duvarı seviyesinde keser, istek PHP'ye hiç ulaşmaz. Yoğun kaba kuvvet trafiğinde aradaki kaynak farkı belirgindir.

Teklif ve Uygunluk

Bir fikriniz mi var?
Yarım cümle de olur.