Fail2ban সবার আগে বসানো হয় এবং সাধারণত সেখানেই থেমে যায়: প্যাকেজ বসানো, সেবা চলছে, sshd আপাতদৃষ্টিতে ঢাকা। ছয় মাস পরে জানা যায় jail এমন একটা ফাইল পড়ছে যা এই সিস্টেমে নেই-ই, আর বাকি সব — মেইল, কন্ট্রোল প্যানেল, সাইটের লগইন ফর্ম — কখনও ঢাকাই পড়েনি।

চলুন দেখি সাইটসহ সাধারণ একটা VPS-এ কী চালু করা দরকার, সেখানে কোন সংখ্যা বসাবেন, আর কীভাবে নিশ্চিত হবেন যে jail কাজ করছে, কেবল কনফিগে উপস্থিত নয়।

আগে যাচাই করুন sshd আদৌ কিছু ধরে কি না

একটি কমান্ড:

sudo fail2ban-client status sshd

ফলাফলে Currently failed, Total failedTotal 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-sasldovecot — নিজের মেইল চালালে অপরিহার্য। মেইলবক্সে পাসওয়ার্ড অনুমান অবিরত চলে এবং সাধারণত কেউ তা দেখে না।
[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-এর তালিকা, এখন কে আটকানো, আর চেষ্টাগুলো কোথা থেকে আসে।