يُثبَّت Fail2ban أولًا، وعند هذا الحد ينتهي الأمر عادة: الحزمة موجودة، والخدمة تعمل، و sshd محمي على ما يبدو. وبعد ستة أشهر يتبيّن أن السجن يقرأ ملفًا غير موجود في هذا النظام، وأن كل ما عداه — البريد، ولوحة التحكم، ونموذج الدخول في الموقع — لم يكن محميًا قط.
لنستعرض ما يستحق التفعيل على خادم VPS عادي به موقع، وأي أرقام تضعها هناك، وكيف تتأكد أن السجن يعمل بدل أن يكون مجرد موجود في الإعداد.
تحقّق أولًا أن sshd يلتقط شيئًا
أمر واحد:
sudo fail2ban-client status sshd
يحتوي المخرج على أسطر Currently failed وTotal failed وTotal banned. إذا كان Total failed صفرًا على خادم بقي على الإنترنت يومًا واحدًا على الأقل، فالسجن لا يعمل. قارن ذلك بالواقع:
sudo lastb | wc -l
آلاف المحاولات الفاشلة في lastb مقابل أصفار في Fail2ban تعني شيئًا واحدًا بالضبط: المرشّح ينظر إلى المكان الخطأ.
السبب الأشيع هو Debian 12. فهو لم يعد يثبّت rsyslog افتراضيًا، والملف /var/log/auth.log ببساطة غير موجود، بينما السجن الافتراضي sshd مضبوط لقراءة هذا الملف بالذات. ولا توجد رسالة خطأ عن ذلك: الخدمة تبدأ، والحالة تُطبع، والعدادات تبقى على الصفر. الحل هو الانتقال إلى سجل 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.
السجن الذي يغيّر الصورة: recidive
ذاكرة السجن العادي قصيرة: خمس محاولات في عشر دقائق، وساعة حظر، وبعد ساعة يبدأ كل شيء من جديد. البوت يتعايش مع ذلك بارتياح وسيعود غدًا وبعد غد. وrecidive يسدّ هذه الفجوة بالضبط: فهو يقرأ لا سجل النظام بل سجل Fail2ban نفسه، أي أنه يحظر من حظره Fail2ban من قبل.
[recidive]
enabled = true
bantime = 1w
findtime = 1d
maxretry = 5
اقرأ ذلك كـ «حُظر خمس مرات في يوم، يختفي لأسبوع». يحتاج السجن إلى الملف /var/log/fail2ban.log، فإن نقلت تسجيل Fail2ban نفسه إلى syslog فسيحتاج recidive هو الآخر إلى backend = systemd.
عمليًا يكون أثر هذا السجن الواحد أوضح عادة من الضبط الدقيق لكل ما عداه: يتساقط الزوّار الدائمون ولا يبقى في السجلات سوى خلفية جديدة.
ماذا تفعّل أيضًا حين يستضيف الخادم موقعًا
بترتيب تنازلي للفائدة:
nginx-http-authأوapache-auth— تخمين ضد المصادقة الأساسية. مطلوب إذا كانت لوحة الإدارة أو موقع الاختبار خلف كلمة مرور من خادم الويب؛nginx-botsearch— مسح المسارات المعروفة:/wp-login.php،/phpmyadmin،/.env. هذا ليس اختراقًا بل استطلاعًا، وهو ما يسبق كل شيء آخر؛nginx-limit-req— لا يعمل إلا إذا كانlimit_req_zoneمعرّفًا في Nginx نفسه؛ وبدون ذلك يكون السجن مفعّلًا وعديم الفائدة؛postfix-saslوdovecot— ضروريان إذا كان لديك بريدك الخاص. تخمين كلمات مرور صناديق البريد مستمر ولا يراقبه أحد عادة.
[nginx-botsearch]
enabled = true
logpath = /var/log/nginx/access.log
نموذج الدخول في الموقع نفسه قصة منفصلة. فالتطبيق ليس لديه سجل خاص بعمليات الدخول الفاشلة، وفي access.log تبدو المحاولة الفاشلة كطلب POST عادي بحالة 200 أو 302 — لا يميّزها أي مرشّح عام عن المحاولة الناجحة. والخياران هما: أن تجعل التطبيق يكتب الإخفاقات في syslog (لدى معظم أنظمة إدارة المحتوى إضافة لذلك)، أو أن تحدّ من معدل الطلبات إلى صفحة الدخول. والثاني محدِّد لا كاشف، ومن الأفضل معرفة ذلك مسبقًا.
الأرقام
bantime = 10m هي القيمة الافتراضية التي تجعل الناس يشطبون Fail2ban كأداة عديمة الجدوى: عشر دقائق تكفي البوت ليعود. ساعة للحظر الأول مع recidive لأسبوع تعمل أفضل بكثير من الحظر الدائم، الذي يتحوّل مع الوقت إلى قائمة قواعد لا تنتهي.
maxretry = 3 لـ SSH طريقة مضمونة لقفل نفسك في الخارج. خمس محاولات في عشر دقائق تقطع التخمين بالجودة نفسها.
التخمين البطيء — محاولة كل خمس دقائق — لن يقع أبدًا داخل 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) كمعرفة بتجربة الآخرين.
وثمة مشكلة منفصلة: كل هذا يحتاج إلى نظرة من حين لآخر. لا أحد يكتب fail2ban-client status لكل سجن أسابيع متتالية، ويُلاحَظ ارتفاع عدد حالات الحظر بعد أن يكون شيء ما قد تعطّل. في صفحات العرض أدناه تجتمع البيانات نفسها على صفحة واحدة: قائمة السجون، ومن هو محظور الآن، ومن أين تأتي المحاولات.