Fail2ban, Python ile yazılmış log tabanlı bir saldırı önleme aracı. Çalışma mantığı oldukça basit, ama bir o kadar da etkili:
- İzleme: Belirlediğiniz log dosyalarını (örneğin
/var/log/auth.log) sürekli takip eder.
- Eşleştirme: Önceden tanımlı düzenli ifadelerle (regex) başarısız giriş, kötü niyetli istek ya da tarama denemelerini yakalar.
- Yasaklama: Belirli bir zaman dilimi içinde eşik değeri aşan IP adreslerini iptables, nftables veya firewalld kurallarıyla engeller.
- Serbest Bırakma: Yasak süresi dolduğunda IP'yi sessizce güvenlik duvarından kaldırır.
Şimdi gelelim ilginç kısma. CrowdSec, Wazuh ve fail-secure gibi modern alternatifler 2025-2026'da ciddi popülerlik kazanmış olsa da Fail2ban; düşük kaynak tüketimi, geniş topluluk filtre ekosistemi ve neredeyse her Linux dağıtımında varsayılan paket olarak bulunması sayesinde küçük-orta ölçekli sunucular için hâlâ ilk tercih olmaya devam ediyor. Üstelik 2025'in sonunda çıkan Fail2ban 1.1.0 sürümü; iyileştirilmiş IPv6 desteği, yeni filtreler ve performans optimizasyonları getirdi (özellikle systemd backend tarafındaki iyileştirmeler dikkat çekici).
Fail2ban'ın Sınırları
Şunu net söyleyelim: Fail2ban sıfır gün (zero-day) saldırılarını ya da uygulama katmanındaki karmaşık tehditleri tespit edemez. Saldırgan farklı IP adreslerinden eş zamanlı olarak (yani dağıtık biçimde) geliyorsa, Fail2ban tek başına yetersiz kalır. Bu yüzden Fail2ban'ı; ModSecurity gibi bir WAF, CrowdSec ya da Cloudflare gibi katman 7 koruma araçlarıyla birleştirmek çok daha sağlıklı bir yaklaşım.
Kurulum: Ubuntu, Debian, RHEL ve Rocky Linux
Ubuntu 24.04 ve Debian 12 Üzerinde Kurulum
sudo apt update
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban
RHEL 9, Rocky Linux 9 ve AlmaLinux 9 Üzerinde Kurulum
Burada Fail2ban EPEL deposunda yer alıyor, o yüzden önce onu eklememiz gerek:
sudo dnf install -y epel-release
sudo dnf install -y fail2ban fail2ban-firewalld
sudo systemctl enable --now fail2ban
Kurulumu Doğrulama
sudo fail2ban-client version
sudo fail2ban-client status
Çıktı aşağı yukarı şuna benzemeli:
Status
|- Number of jail: 1
`- Jail list: sshd
Yapılandırma Mimarisi: jail.conf, jail.local ve jail.d
Yeni başlayanların yaptığı en yaygın hata? Doğrudan /etc/fail2ban/jail.conf dosyasını düzenlemek. Sakın yapmayın, çünkü bu dosya paket güncellemelerinde üzerine yazılır ve emeğiniz çöp olur. Doğru yöntem şöyle:
/etc/fail2ban/jail.conf — Asla dokunmayın; yalnızca referans olarak okuyun.
/etc/fail2ban/jail.local — Genel ayarları (DEFAULT bölümü) ezmek için kullanın.
/etc/fail2ban/jail.d/*.conf — Servis bazlı yapılandırmaları (nginx.conf, postfix.conf vb.) buraya ekleyin.
Benim önerdiğim yaklaşım: genel varsayılanlar jail.local içine, servise özel ayarlar ise jail.d/ dizinine. Fail2ban yapılandırmaları yüklerken dosyaları alfabetik sırayla işler ve sonraki tanımlar öncekileri ezer; yani isimlendirme önemli.
Temel jail.local Yapılandırması
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Aslında bence daha temiz bir yol var: jail.local dosyasını tamamen sıfırdan oluşturup yalnızca üzerine yazılması gereken anahtarları belirtmek. Şöyle:
[DEFAULT]
# Yasaklamadan muaf tutulacak adresler (kendi statik IP'niz, iç ağ)
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 192.168.0.0/16 203.0.113.42
# Yasak süresi (saniye). -1 = kalıcı yasak
bantime = 3600
# Eşik penceresi (saniye)
findtime = 600
# Bu süre içinde maksimum başarısız deneme
maxretry = 5
# Tekrar suç işleyenler için artan yasak süresi
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 1w
# Engelleme yöntemi (Ubuntu 24.04 için iptables-multiport, RHEL 9 için firewallcmd-ipset)
banaction = iptables-multiport
banaction_allports = iptables-allports
# Loglama
loglevel = INFO
logtarget = /var/log/fail2ban.log
# DNS arama (yavaş ve güvenilmez, kapalı tutun)
usedns = no
# Bildirim e-postası (opsiyonel)
destemail = [email protected]
sender = [email protected]
mta = sendmail
action = %(action_mwl)s
Çok önemli: ignoreip satırına mutlaka kendi yönetim IP adresinizi ekleyin. Yoksa bir gün yanlış parolayla birkaç kez denersiniz ve kendi sunucunuzdan kendinizi kilitlersiniz — bu durumun bana yaşattıklarını anlatamam, gerçekten can sıkıcı.
SSH İçin Temel Koruma (sshd jail)
SSH, internete açık her sunucunun en sık saldırıya uğrayan servisi. Tartışmasız. Aşağıdaki yapılandırmayı /etc/fail2ban/jail.d/sshd.local dosyasına ekleyin:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
findtime = 300
bantime = 86400
# Agresif mod: port tarama ve protokol tarama denemelerini de engeller
mode = aggressive
Mode parametresi nedir, ne işe yarar?
normal — Sadece başarısız giriş denemeleri.
ddos — Bağlantı sonrası kapatılan oturumları yakalar.
extra — Geçersiz kullanıcı adı denemelerini de içerir.
aggressive — Hepsini birden kapsar (en güvenlisi, ama meşru hatalı denemeleri de yakalayabilir).
Yapılandırmayı yükleyin ve durumu kontrol edin:
sudo systemctl reload fail2ban
sudo fail2ban-client status sshd
Örnek çıktı şöyle görünür:
Status for the jail: sshd
|- Filter
| |- Currently failed: 4
| |- Total failed: 1287
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 12
|- Total banned: 348
`- Banned IP list: 45.143.200.12 89.248.165.74 ...
Web Sunucuları İçin Koruma: Nginx ve Apache
Nginx: Yetkilendirme ve 4xx Saldırılarına Karşı
Şimdi sıra web sunucularında. /etc/fail2ban/jail.d/nginx.local dosyasını şöyle hazırlayın:
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
findtime = 600
bantime = 7200
[nginx-botsearch]
enabled = true
filter = nginx-botsearch
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 2
findtime = 300
bantime = 86400
[nginx-bad-request]
enabled = true
filter = nginx-bad-request
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 600
bantime = 3600
[nginx-limit-req]
enabled = true
filter = nginx-limit-req
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 10
findtime = 600
bantime = 3600
Küçük bir not: nginx-limit-req jail'inin çalışabilmesi için Nginx tarafında limit_req_zone direktifinin tanımlı olması gerekiyor. Yoksa boş duvara konuşur.
Apache HTTP Server
Apache kullanıyorsanız /etc/fail2ban/jail.d/apache.local şu şekilde olmalı:
[apache-auth]
enabled = true
filter = apache-auth
port = http,https
logpath = /var/log/apache2/error.log
maxretry = 3
findtime = 600
bantime = 7200
[apache-badbots]
enabled = true
filter = apache-badbots
port = http,https
logpath = /var/log/apache2/access.log
maxretry = 1
bantime = 86400
[apache-noscript]
enabled = true
filter = apache-noscript
port = http,https
logpath = /var/log/apache2/error.log
maxretry = 3
bantime = 86400
[apache-overflows]
enabled = true
filter = apache-overflows
port = http,https
logpath = /var/log/apache2/error.log
maxretry = 1
bantime = 604800
Mail Sunucuları İçin Koruma: Postfix ve Dovecot
Mail sunucusu işletiyorsanız Fail2ban olmazsa olmaz. SMTP kimlik bilgisi denemeleri saatte binlerle ölçülebilir. /etc/fail2ban/jail.d/mail.local dosyası:
[postfix]
enabled = true
filter = postfix
port = smtp,465,submission
logpath = /var/log/mail.log
maxretry = 3
bantime = 86400
[postfix-sasl]
enabled = true
filter = postfix-sasl
port = smtp,465,submission,imap,imaps,pop3,pop3s
logpath = /var/log/mail.log
maxretry = 3
bantime = 86400
[dovecot]
enabled = true
filter = dovecot
port = pop3,pop3s,imap,imaps,submission,465,sieve
logpath = /var/log/mail.log
maxretry = 5
bantime = 86400
WordPress İçin Özel Filtre
WordPress'in wp-login.php sayfasına yönelik kaba kuvvet saldırıları o kadar yaygın ki, çoğu WordPress sitesinin trafiğinin önemli bir kısmı bot taramalarından oluşuyor. Hadi bunu durduralım.
Önce filtre dosyasını oluşturun: /etc/fail2ban/filter.d/wordpress-auth.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-login.php HTTP.*" 200
^<HOST> .* "POST /xmlrpc.php HTTP.*" 200
ignoreregex =
Sonra jail tanımı: /etc/fail2ban/jail.d/wordpress.local
[wordpress-auth]
enabled = true
filter = wordpress-auth
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 300
bantime = 86400
Özel Filtre Yazma: Adım Adım
Hazır filtreler ihtiyacınızı karşılamadığında kendi filtrenizi yazabilirsiniz. Bence Fail2ban'ın en güçlü yanı bu esneklik. Örnek olarak özel bir API uç noktasına gelen başarısız token doğrulama denemelerini engelleyen bir filtre kuralım.
Diyelim ki log formatımız şöyle (örneğin /var/log/myapi/auth.log):
2026-05-07T10:23:45+03:00 ERROR auth.token: Invalid token from 198.51.100.34 user=admin
2026-05-07T10:23:48+03:00 ERROR auth.token: Invalid token from 198.51.100.34 user=root
Filtre dosyası: /etc/fail2ban/filter.d/myapi-auth.conf
[Definition]
failregex = ^.* ERROR auth\.token: Invalid token from <HOST> user=.*$
ignoreregex =
datepattern = ^%%Y-%%m-%%dT%%H:%%M:%%S%%z
Filtreyi mutlaka test edin (yazdığınız regex doğru çalışmıyorsa Fail2ban hiç şikayet etmeden sessizce eşleşmeyebilir):
sudo fail2ban-regex /var/log/myapi/auth.log /etc/fail2ban/filter.d/myapi-auth.conf
Çıktıda eşleşme sayısını göreceksiniz. Her şey yolundaysa jail'i devreye alın:
[myapi-auth]
enabled = true
filter = myapi-auth
port = 8080
logpath = /var/log/myapi/auth.log
maxretry = 3
findtime = 600
bantime = 7200
nftables ile Entegrasyon (2026 Önerilen Yaklaşım)
Modern Linux dağıtımları (Debian 12+, Ubuntu 22.04+, RHEL 9+) varsayılan olarak nftables kullanıyor ve dürüst olmak gerekirse iptables artık yavaşça emekli oluyor. Fail2ban 1.0+ sürümü nftables için yerleşik destek sunuyor. jail.local dosyanızda banaction'ı şöyle değiştirin:
[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables-allports
chain = INPUT
nftables tablosunun varlığını kontrol edin:
sudo nft list ruleset | grep -A 5 fail2ban
Eğer Fail2ban kurulumu sırasında nftables ailesi oluşmadıysa, manuel olarak tetikleyebilirsiniz:
sudo systemctl restart fail2ban
sudo nft list table inet f2b-table
nftables ile güvenlik duvarı yapılandırması hakkındaki detaylı rehberimiz bu konuda işin teorisine ve pratiğine derinlemesine giriyor.
fail2ban-client ile Yönetim
Fail2ban'ı çalışır durumdayken yönetmek için fail2ban-client komutunu kullanıyoruz. Aslında bu küçük araç, günlük operasyonların belkemiği.
Sık Kullanılan Komutlar
# Tüm aktif jail'leri listele
sudo fail2ban-client status
# Belirli bir jail'in detaylı durumu
sudo fail2ban-client status sshd
# Bir IP'yi manuel olarak yasakla
sudo fail2ban-client set sshd banip 198.51.100.42
# Bir IP'yi yasaktan çıkar
sudo fail2ban-client set sshd unbanip 198.51.100.42
# Bir IP'nin yasaklı olup olmadığını sorgula
sudo fail2ban-client get sshd banip --with-time
# Tüm yasakları temizle
sudo fail2ban-client unban --all
# Yapılandırmayı yeniden yükle (yeniden başlatmadan)
sudo fail2ban-client reload
# Belirli bir jail'i yeniden başlat
sudo fail2ban-client reload sshd
# Bir IP'yi kalıcı olarak ignore listesine ekle
sudo fail2ban-client set sshd addignoreip 203.0.113.10
Yasaklanmış IP'leri JSON Formatında Almak
sudo fail2ban-client banned
Çıktı şu şekilde olur:
[{'sshd': ['45.143.200.12', '89.248.165.74']}, {'nginx-botsearch': ['185.220.101.5']}]
Bildirim ve Webhook Aksiyonları
E-posta Bildirimi
Yasaklama anında ilgili log satırlarıyla beraber e-posta almak için action_mwl kullanabilirsiniz:
[DEFAULT]
destemail = [email protected]
sender = [email protected]
mta = sendmail
action = %(action_mwl)s
Bu aksiyon adlarının ne anlama geldiğine bir bakalım:
action_ — Sadece engelleme.
action_mw — Engelleme + WHOIS sorgulu e-posta.
action_mwl — Engelleme + WHOIS + ilgili log satırları (en bilgilendirici olanı).
Slack/Discord Webhook Bildirimi
E-posta yerine Slack ya da Discord'a bildirim almak isteyenler için özel bir aksiyon dosyası oluşturalım: /etc/fail2ban/action.d/slack-webhook.conf
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = curl -X POST -H 'Content-type: application/json' \
--data '{"text":"Fail2ban: <name> jail tarafından yasaklandı."}' \
https://hooks.slack.com/services/XXX/YYY/ZZZ
actionunban =
[Init]
name = default
Sonra ilgili jail'de aksiyonu çağırın:
[sshd]
action = %(banaction)s[name=%(__name__)s, port="%(port)s"]
slack-webhook[name=%(__name__)s]
Performans ve Optimizasyon
Yüksek trafikli sunucularda Fail2ban'ı verimli tutmak istiyorsanız, şu ipuçlarını aklınızdan çıkarmayın:
- Backend seçimi: Modern dağıtımlarda
backend = systemd kullanın. polling ya da pyinotify seçeneklerine kıyasla çok daha verimli.
- usedns = no: DNS aramaları yavaş ve güvenilmez. Kapalı tutun, hayatınız kolaylaşsın.
- Yasak veri tabanını sınırlayın:
dbpurgeage = 86400 ile eski kayıtları otomatik temizleyin.
- ipset kullanımı: Çok sayıda yasaklı IP olan ortamlarda
banaction = iptables-ipset-proto6-allports performansı önemli ölçüde artırır.
- Gereksiz jail'leri kapatın: Sunucunuzda olmayan servislerin jail'lerini etkinleştirmek hem CPU yer hem de gereksiz log tarar.
Veri Tabanı Boyutunu Kontrol Etme
sudo du -h /var/lib/fail2ban/fail2ban.sqlite3
sudo sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "SELECT COUNT(*) FROM bans;"
Veri tabanı haddinden fazla şişmişse manuel temizleme yapabilirsiniz:
sudo sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "DELETE FROM bans WHERE timeofban < strftime('%s', 'now', '-30 days');"
sudo sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "VACUUM;"
Yaygın Sorunlar ve Çözümleri
Sorun 1: "Found no accessible config files for 'filter.d/foo'"
Klasik bir hata. Filtre dosyasının doğru dizinde olduğundan ve izinlerinin uygun olduğundan emin olun:
ls -la /etc/fail2ban/filter.d/foo.conf
sudo chmod 644 /etc/fail2ban/filter.d/foo.conf
Sorun 2: SSH jail çalışmıyor (systemd journal kullanan dağıtımlar)
Ubuntu 22.04+ ve RHEL 9+ sistemlerde /var/log/auth.log dosyası bulunmayabilir — çünkü loglar artık doğrudan systemd journal'a gidiyor. Bu durumda backend'i şöyle değiştirin:
[sshd]
backend = systemd
Sorun 3: IPv6 adresleri yasaklanmıyor
Fail2ban 1.0+ sürümünde IPv6 desteği var, ama banaction'ın da IPv6 destekli olduğundan emin olmanız lazım:
banaction = nftables-multiport
allowipv6 = auto
Sorun 4: Yanlışlıkla kendi IP'mden yasaklandım, nasıl çıkarım?
Konsol erişiminiz hâlâ varsa kolay:
sudo fail2ban-client unban <your-ip>
Yoksa, sağlayıcınızın acil kurtarma konsolunu (Hetzner Rescue System, AWS EC2 Instance Connect vb.) kullanmak zorunda kalırsınız. Önleyici tedbir olarak başta da söylediğim gibi: ignoreip listesine yönetim IP'nizi mutlaka ekleyin. Beni bu konuda dinleyin.
Sorun 5: Çok yüksek CPU kullanımı
Çok büyük log dosyalarını polling backend ile izlemek CPU'yu kıyasıya zorlar. Çözüm basit: backend = systemd ya da backend = pyinotify kullanın ve eski log dosyalarını logrotate ile makul boyutta tutun.
Fail2ban vs CrowdSec: 2026 Karşılaştırması
Son birkaç yıldır CrowdSec, Fail2ban'a güçlü bir alternatif olarak yükselişte. İki aracı kıyaslayalım, böylece kendi senaryonuza hangisinin uyduğuna karar verebilirsiniz:
| Özellik | Fail2ban | CrowdSec |
| Mimari | Yerel, log tabanlı | Dağıtık, topluluk tabanlı |
| Tehdit istihbaratı | Yok (yerel) | Global blocklist (CTI) |
| Kurulum karmaşıklığı | Düşük | Orta |
| Kaynak tüketimi | Çok düşük | Düşük-orta |
| Topluluk paylaşımı | Yok | Var (P2P) |
| Yapılandırma esnekliği | Yüksek (regex) | Yüksek (YAML) |
| 2026'da öneri | Tek sunucu, basit ortamlar | Filo, üretim ortamları |
Sonuç: Tek bir VPS ya da küçük altyapı için Fail2ban fazlasıyla yeterli ve bakımı çok daha az. Çoklu sunucu, container ortamı veya merkezi tehdit istihbaratı arıyorsanız CrowdSec gerçekten dikkate değer. İkisini birlikte de kullanabilirsiniz, kimse karışmaz.
Doğrulama: Saldırıyı Simüle Edin
Yapılandırmanın çalıştığını doğrulamak için başka bir makineden (veya VPN üzerinden) kasıtlı yanlış SSH girişleri yapalım:
for i in {1..5}; do ssh [email protected]; done
Sunucu tarafında izleyin:
sudo tail -f /var/log/fail2ban.log
sudo fail2ban-client status sshd
Test bittiğinde test IP'nizi yasaktan çıkarmayı unutmayın (yoksa sonradan yasak çözmekle uğraşırsınız):
sudo fail2ban-client set sshd unbanip <test-ip>
Sıkça Sorulan Sorular (SSS)
Fail2ban kalıcı yasak (permanent ban) nasıl tanımlanır?
Belirli bir jail için bantime = -1 tanımlamanız yeterli. Daha şık bir yöntem ise bantime.increment = true ve bantime.maxtime = -1 kombinasyonu — bu, tekrar suç işleyenleri zamanla kalıcı olarak yasaklayan dinamik bir yapı kurar.
Fail2ban CloudFlare arkasında çalışır mı?
CloudFlare gibi reverse proxy'ler arkasındaki sunucular tüm istekleri proxy IP'sinden alır. Bu da Fail2ban'ı kafadan ezmek için bir reçete. Çözüm: web sunucunuzun X-Forwarded-For başlığını log'a yazması gerekir. Nginx için log_format direktifine $http_x_forwarded_for eklemeli ve filtrenizi buna göre güncellemelisiniz. Daha temiz bir yol istiyorsanız, CloudFlare API ile entegre çalışan cloudflare-token aksiyonunu kullanarak yasakları doğrudan CloudFlare seviyesine taşıyabilirsiniz.
Fail2ban Docker container'larını koruyabilir mi?
Evet ama bir incelik var: host üzerinde çalışan Fail2ban'ın container loglarını okuyabilmesi gerekir. docker logs çıktısını bir dosyaya yönlendirip o dosyayı izlemek en yaygın yöntem. Container içinde çalışan servisler için filtre yazarken IP adreslerinin proxy başlıklarından geldiğine de dikkat edin. Container yoğun ortamlarda CrowdSec ya da Falco genellikle daha pratik bir tercih oluyor.
Fail2ban yapılandırma değişikliklerini test etmenin güvenli yolu nedir?
Yeni filtre yazıyorsanız fail2ban-regex komutunu mutlaka kullanın: fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/myfilter.conf. Bu komut size hangi log satırlarının eşleştiğini, hangilerinin atlandığını gösterir. Üretim ortamına uygulamadan önce bir test sunucusunda doğrulamak en güvenli yaklaşım — bir keresinde "olur abi, çalışır" deyip üretime attım, sonra 200 IP'yi yanlışlıkla yasakladım, yaşadığım pişmanlık hâlâ aklımda.
Yasaklanmış IP'leri başka sunucularla nasıl paylaşırım?
Fail2ban'ın doğal bir paylaşım mekanizması yok. Üç seçeneğiniz var: (1) fail2ban-client banned çıktısını periyodik olarak Ansible/Salt ile diğer sunuculara dağıtmak, (2) ortak bir nftables set'ini etcd ya da Consul üzerinden senkronize etmek, (3) CrowdSec'e geçmek — topluluk tabanlı blocklist tam olarak bu sorunu çözmek için var zaten.
Sonuç
Sonuç olarak, Fail2ban 2026'da hâlâ Linux sunucularını otomatik saldırılara karşı korumanın en hızlı ve en hafif yollarından biri. Bu rehberdeki yapılandırmaları uyguladığınızda; SSH brute-force, web bot taraması, mail server abuse ve özel uygulama saldırılarına karşı katmanlı bir savunma kurmuş olursunuz. Bir sonraki adım olarak Lynis ile sistem genelinde güvenlik denetimi yapmanızı, ardından çekirdek seviyesinde sıkılaştırma uygulamanızı şiddetle öneririm.
Son bir hatırlatma: Fail2ban tek başına bir gümüş kurşun değil, asla olmadı. SSH anahtar tabanlı kimlik doğrulama, MFA, port knocking ve gereksiz portları kapatma gibi temel önlemleri ihmal etmeyin. Güvenlik bir ürün değil, sürekli bir süreç — en sevdiğim klişe ama doğru olmaktan çıkmıyor.