Fail2ban सबसे पहले लगाया जाता है और आमतौर पर वहीं रुक भी जाता है: पैकेज लगा है, सेवा चल रही है, sshd जाहिरा तौर पर ढका हुआ है। छह महीने बाद पता चलता है कि jail ऐसी फ़ाइल पढ़ रहा है जो इस सिस्टम पर है ही नहीं, और बाकी सब — मेल, कंट्रोल पैनल, साइट का लॉगिन फ़ॉर्म — कभी ढका ही नहीं था।

आइए देखें कि साइट वाले एक सामान्य VPS पर क्या चालू करने लायक है, वहाँ कौन से अंक रखें, और कैसे तय करें कि jail काम कर रहा है, महज़ कॉन्फ़िग में मौजूद नहीं है।

पहले जाँचें कि sshd कुछ पकड़ता भी है

एक कमांड:

sudo fail2ban-client status sshd

आउटपुट में Currently failed, Total failed और Total banned की पंक्तियाँ होती हैं। अगर कम से कम एक दिन से इंटरनेट पर मौजूद सर्वर पर Total failed शून्य है, तो jail काम नहीं कर रहा। इसे हक़ीक़त से मिलाएँ:

sudo lastb | wc -l

lastb में हज़ारों असफल कोशिशें और Fail2ban में शून्य — इसका ठीक एक ही मतलब है: फ़िल्टर ग़लत जगह देख रहा है।

सबसे आम कारण Debian 12 है। वह अब डिफ़ॉल्ट रूप से rsyslog नहीं लगाता, फ़ाइल /var/log/auth.log होती ही नहीं, और मानक sshd jail उसी फ़ाइल को पढ़ने के लिए सेट है। इस बारे में कोई त्रुटि नहीं आती: सेवा चालू होती है, स्थिति दिखती है, गिनतियाँ शून्य पर रहती हैं। समाधान है systemd के जर्नल पर जाना:

[sshd]
enabled = true
backend = systemd

दूसरा विकल्प है rsyslog को पैकेज के रूप में लौटा देना, अगर सादा पाठ वाली auth.log दूसरे औज़ारों के लिए ज़रूरी हो। Ubuntu 24.04 भी ऐसा ही व्यवहार करता है।

अपनी सेटिंग्स कहाँ रखें

/etc/fail2ban/jail.conf को हाथ न लगाएँ: पैकेज अपडेट पर वह ऊपर से लिख दी जाती है, और वहाँ किया हर बदलाव किसी दिन चुपचाप ग़ायब हो जाएगा। आपकी अपनी सेटिंग्स /etc/fail2ban/jail.local में जाती हैं — यह फ़ाइल आख़िर में पढ़ी जाती है और साझा फ़ाइल पर भारी पड़ती है।

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.25
bantime  = 1h
findtime = 10m
maxretry = 5
backend  = systemd

अपने पते के साथ ignoreip विलासिता नहीं, बीमा है: टाइपो के कारण ख़ुद को बाहर कर लेना जितना लगता है उससे आसान है। अगर स्थायी पता नहीं है, तो SSH के अलावा अंदर आने का दूसरा रास्ता रखें — प्रदाता का कंसोल या VNC।

तस्वीर बदलने वाला jail: recidive

सामान्य jail की याददाश्त छोटी होती है: दस मिनट में पाँच कोशिशें, एक घंटे का प्रतिबंध, और एक घंटे बाद सब कुछ फिर से शुरू। बॉट इसके साथ आराम से जीता है और कल भी लौटेगा और परसों भी। recidive ठीक इसी अंतर को बंद करता है: वह सिस्टम लॉग नहीं, बल्कि ख़ुद Fail2ban का लॉग पढ़ता है, यानी उसे रोकता है जिसे Fail2ban पहले ही रोक चुका है।

[recidive]
enabled  = true
bantime  = 1w
findtime = 1d
maxretry = 5

इसे इस तरह पढ़ें: «एक दिन में पाँच बार रोका गया — एक हफ़्ते के लिए बाहर»। इस jail को फ़ाइल /var/log/fail2ban.log चाहिए, इसलिए अगर आपने Fail2ban की अपनी लॉगिंग syslog में भेज दी है, तो recidive को भी backend = systemd चाहिए होगा।

व्यवहार में इस एक jail का असर आमतौर पर बाकी सबकी बारीक ट्यूनिंग से ज़्यादा दिखता है: नियमित आगंतुक हट जाते हैं और लॉग में सिर्फ़ ताज़ा पृष्ठभूमि बचती है।

सर्वर पर साइट हो तो और क्या चालू करें

उपयोगिता के घटते क्रम में:

  • nginx-http-auth या apache-auth — बुनियादी प्रमाणीकरण पर पासवर्ड का अनुमान। ज़रूरी है अगर एडमिन क्षेत्र या staging साइट वेब सर्वर के पासवर्ड के पीछे हो;
  • nginx-botsearch — जाने-पहचाने रास्तों की खोज: /wp-login.php, /phpmyadmin, /.env। यह सेंध नहीं, टोह है, और यही बाकी सब से पहले आती है;
  • nginx-limit-req — तभी काम करता है जब ख़ुद Nginx में limit_req_zone परिभाषित हो; इसके बिना jail चालू है और बेकार है;
  • postfix-sasl और dovecot — अपनी मेल चलाते हों तो अनिवार्य। मेलबॉक्सों पर पासवर्ड का अनुमान लगातार चलता है और आमतौर पर उसे कोई नहीं देखता।
[nginx-botsearch]
enabled = true
logpath = /var/log/nginx/access.log

साइट का अपना लॉगिन फ़ॉर्म अलग कहानी है। एप्लिकेशन के पास असफल लॉगिन का अपना लॉग नहीं होता, और access.log में असफल कोशिश 200 या 302 वाले सामान्य POST जैसी दिखती है — किसी भी सामान्य फ़िल्टर के लिए सफल कोशिश से अलग नहीं। दो रास्ते हैं: या एप्लिकेशन से असफलताएँ syslog में लिखवाएँ (ज़्यादातर सामग्री प्रबंधन प्रणालियों में इसके लिए प्लगइन है), या लॉगिन पेज पर अनुरोधों की दर सीमित करें। दूसरा पहचान नहीं, सीमक है, और यह पहले से जान लेना बेहतर है।

अंक

bantime = 10m वही डिफ़ॉल्ट है जिसकी वजह से लोग Fail2ban को बेकार मान लेते हैं: दस मिनट बॉट के लौटने के लिए काफ़ी हैं। पहले प्रतिबंध के लिए एक घंटा और साथ में हफ़्ते भर का recidive स्थायी प्रतिबंधों से कहीं बेहतर काम करता है, जो समय के साथ नियमों की मीलों लंबी सूची बन जाते हैं।

SSH के लिए maxretry = 3 ख़ुद को बाहर कर लेने का भरोसेमंद तरीका है। दस मिनट में पाँच कोशिशें भी उतनी ही अच्छी तरह अनुमान लगाना काट देती हैं।

धीमा अनुमान — हर पाँच मिनट में एक कोशिश — कभी findtime के अंदर नहीं आएगा। यह खिड़की को एक दिन तक खींचने का कारण नहीं: आपको अपने ही साथियों पर झूठे प्रतिबंध मिलेंगे। धीमे अनुमान के ख़िलाफ़ सीमा नहीं, बल्कि बंद किया गया पासवर्ड प्रमाणीकरण काम करता है।

पक्का करें कि प्रतिबंध पैकेटों तक पहुँचता है

Fail2ban सिर्फ़ एक बाहरी कमांड चलाता है। अगर banaction उससे मेल नहीं खाता जो वाकई ट्रैफ़िक छानता है, तो लॉग में ख़ुशनुमा Ban 198.51.100.7 पंक्तियाँ भरती रहेंगी और पैकेट आते रहेंगे। Debian 12 डिफ़ॉल्ट रूप से nftables इस्तेमाल करता है, और UFW चालू हो तो सही विकल्प banaction = ufw है। जाँचने के लिए:

sudo nft list ruleset | grep -c f2b
sudo iptables -S | grep f2b

दोनों में से कम से कम एक को नियम दिखाने चाहिए। और ख़ुद फ़िल्टर को हमले का इंतज़ार किए बिना जाँचा जा सकता है:

sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf

आउटपुट के नीचे लिखा होता है कि कितनी पंक्तियाँ मेल खाईं। शून्य का मतलब है कि फ़िल्टर और लॉग एक-दूसरे से नहीं मिलते, और आगे कुछ भी सेट करने का कोई मतलब नहीं।

Fail2ban क्या नहीं करता

यह वितरित अनुमान से नहीं बचाता: एक-एक कोशिश वाले हज़ार पते किसी भी सेटिंग पर सीमा तक नहीं पहुँचेंगे। यह कारण नहीं मिटाता — रोका गया पता कमज़ोर पासवर्ड को रद्द नहीं करता। और यह प्रतिष्ठा के बारे में कुछ नहीं जानता: जिस पते ने कल दूसरों के सर्वर तोड़ने में बिताया, वह इसके लिए तब तक साफ़ है जब तक आपके यहाँ न आए। इसीलिए व्यवहार में यह संयोजन बनता है: पासवर्ड की जगह कुंजियाँ, शोर के सीमक के रूप में Fail2ban, और दूसरों के अनुभव के ज्ञान के रूप में साझा ब्लॉकलिस्ट (CrowdSec)।

अलग समस्या यह है कि इस सब पर कभी-कभी नज़र डालनी पड़ती है। हफ़्तों तक हर jail के लिए fail2ban-client status कोई नहीं लिखता, और प्रतिबंधों की बढ़ती संख्या तब दिखती है जब कुछ टूट चुका हो। नीचे के डेमो पेजों पर वही डेटा एक पन्ने पर है: jail की सूची, अभी कौन रोका गया है, और कोशिशें कहाँ से आती हैं।