FAQ

هذا دليل تثبيت Arcivéo Security Monitor وإعداده وصيانته. الأقسام مقسّمة إلى: نظرة عامة، ونشر لوحة التحكم، وربط أدوات الأمان، والوحدات المدمجة والتشخيص. يمكن نسخ الأوامر بالزر على اليمين.

من أين تبدأ

01. تثبيت اللوحة — اختر الطريقة

تثبيت اللوحة موضّح في صفحات منفصلة خطوة بخطوة. اختر الطريقة:

إن لم تكن متأكدًا، اختر الطريقة التلقائية. يبقى هذا الدليل المرجع الموحّد لـ SSL والأدوات وcron والتشخيص — تشير صفحات التثبيت إلى أقسامه دون أي تكرار.

نظرة عامة

02. ما هو Arcivéo Security Monitor

Arcivéo Security Monitor — لوحة أمان السيرفر. يجمع البيانات من الأدوات المثبتة (Fail2ban وUFW وLynis وModSecurity وAIDE وClamAV وAuditd وCrowdSec وSuricata وFalco وغيرها) ويعرضها في واجهة موحدة تضم لوحة معلومات وخريطة هجمات وصفحات تفصيلية لكل أداة.

المونيتور ليس أداة حماية فعّالة — فهو لا يحجب الهجمات بنفسه. مهمته تجميع المعلومات من الأدوات العاملة بالفعل وعرضها بشكل مريح.

03. كيف يعمل المونيتور على السيرفر

يعمل المونيتور محليًا فقط — يجب تثبيته على نفس السيرفر الذي يراقبه. لا يوجد أي SSH أو API عن بُعد.

تُنفّذ لوحة التحكم جميع الأوامر (fail2ban-client، ufw status، ipset list وغيرها) باسم مستخدم سيرفر الويب (عادةً www-data، وفي لوحات الاستضافة حساب الموقع) بـمجموعة صلاحيات محدودة من sudo — على أدوات محددة فقط، دون وصول root عام. تُحلَّل النتائج وتُعرَض في المتصفح.

إيقاعان في العمل. صفحات اللوحة تسأل الأدوات لحظة فتحها — لذلك ترى دائمًا الحالة الراهنة. وإلى جانب ذلك تعمل في الخلفية مهام مجدولة (cron):

  • كل 5 دقائق — لقطة للحِمل من أجل صفحة «الأداء»؛
  • كل 5 دقائق — مستشعر أحداث الأمان: حظر جديد، تنبيهات IDS، خدمة حماية توقفت، منفذ انفتح (قسم «أحداث الأمان»)؛
  • مرة كل يوم — تقرير الأمان إلى Telegram والبريد، إضافة إلى الفحوص الثقيلة (Lynis وAIDE وClamAV وdebsums وLogwatch)؛
  • كل 15 دقيقة — ملخص الخادم إلى الحساب الشخصي، إن كان مفعّلًا.

القائمة الكاملة للمهام في قسم «جميع مهام cron في مكان واحد».

إذا كان لديك عدة خوادم، ثبّت المونيتور على كل واحد منها على حدة، بنطاق خاص به. ولكي تراها في قائمة واحدة، فعّل ملخص الخوادم (قسم «ملخص الخوادم في الحساب الشخصي»).

04. كيف تُحتسب درجة الأمان

تبدأ الدرجة من القيمة القصوى وتنخفض عند كل مشكلة يتم اكتشافها:

  • UFW غير مُفعّل — −30
  • Fail2ban غير مُشغّل (لا توجد jail نشطة) — −25
  • لا توجد مفاتيح WebAuthn — −15
  • مؤشر تحصين Lynis أقل من 60 — −20؛ 60–79 — −10
  • قائمة IPset ipsum غير محمّلة — −10
  • تهديدات اكتشفها ClamAV — −20
  • تغييرات ملفات AIDE — −15
  • انتهت صلاحية SSL — −30، تنتهي خلال أقل من 14 يومًا — −15، أقل من 30 يومًا — −5
  • CrowdSec مثبّت لكنه غير مُشغّل — −5
  • Suricata مثبّتة لكنها غير مُشغّلة — −5
  • قواعد البيانات/التخزين المؤقت (MySQL، PostgreSQL، Redis…) متاحة من الخارج — −10
  • السماح بتسجيل دخول root عبر SSH (PermitRootLogin yes) — −20
  • تسجيل الدخول بكلمة المرور عبر SSH مفعّل (PasswordAuthentication yes) — −10
  • إعدادات SSH صغيرة: X11Forwarding مفعّل، أو MaxAuthTries أكبر من 3، أو الملف sshd_config مقروء لكل الحسابات — −5
  • تقوية خادم الويب: الاستجابات تكشف إصدار خادم الويب أو PHP، أو طريقة TRACE مفعّلة، أو الترويسة Strict-Transport-Security أو X-Frame-Options غائبة — −5
  • توجد تحديثات أمان بانتظار التثبيت — −5

النتيجة: 80+ = محمي، 60–79 = انتباه، <60 = مُعرّض للخطر.

تُطبّق الخصومات الخاصة بـ ClamAV وAIDE وCrowdSec وSuricata فقط إذا كانت الأداة مثبّتة. يظهر Lynis وAIDE بدون قاعدة بيانات مُهيّأة كـ «لا توجد بيانات» ولا يُخفّضان الدرجة. يُعرض عدد الهجمات اليوم في لوحة التحكم لكنه لا يؤثر على درجة الأمان. لا تُحتسب تقوية خادم الويب إذا لم يستجب أي موقع للفحص.

الإعدادات والترخيص

05. WebAuthn — المصادقة الثنائية

WebAuthn — معيار مصادقة بدون كلمة مرور عبر مفتاح أمان مادي. يدعم YubiKey وTouch ID وFace ID وWindows Hello وPasskey.

بعد تسجيل الدخول بكلمة المرور، يطلب النظام تأكيدًا عبر مفتاح أمان مُسجَّل. حتى لو تسرّبت كلمة المرور، يستحيل الدخول دون المفتاح المادي أو السمة الحيوية.

للإعداد، افتح مفاتيح WebAuthn من القائمة الجانبية واضغط «تسجيل مفتاح». سجّل مفتاحين معًا: إذا فُقد المفتاح الوحيد أو تعطّل، فسيتعذّر الدخول إلى اللوحة عبره.

يعمل WebAuthn عبر HTTPS فقط. على اتصال HTTP لا يتوفر تسجيل المفتاح أو الدخول به.

06. الإشعارات: Telegram والبريد الإلكتروني وwebhook والتنبيهات الفورية

القنوات أربع: Telegram والبريد الإلكتروني وwebhook والتنبيهات الفورية في المتصفح. وهي مستقلة بعضها عن بعض — فعّل ما تشاء منها، أو الأربع جميعًا. وعبر القنوات نفسها يُرسَل تقرير الأمان اليومي وتنبيهات الحِمل وما يعثر عليه مستشعر الأحداث؛ تُضبَط جميعها مرة واحدة هنا، في قسم «الإعدادات».

Telegram. تحتاج إلى توكن البوت وchat id:

  1. في Telegram راسل @BotFather ← /newbot ← ستحصل على توكن بالشكل 123456:ABC....
  2. أرسل إلى بوتك الجديد أي رسالة (كي يتمكن من الرد عليك).
  3. اعرف الـchat id الخاص بك: راسل البوت @userinfobot، أو افتح https://api.telegram.org/bot<TOKEN>/getUpdates وابحث عن "chat":{"id":...}.
  4. أدخل التوكن والـ chat id في «الإعدادات» ← Telegram، ثم اضغط «حفظ وإرسال اختبار».

البريد الإلكتروني. طريقتان للاختيار في «الإعدادات» ← البريد الإلكتروني:

  • SMTP — المضيف والمنفذ (465/SSL أو 587/TLS) واسم المستخدم وكلمة مرور صندوق بريدك؛
  • Resend — API حديث: أدخل مفتاح API (re_...) ونطاق المرسل المؤكَّد.

Webhook. عنوان واحد يقبل POST يكفي لـ Slack وDiscord وMattermost وn8n ومعالِجك الخاص. «الإعدادات» → Webhook: الصق العنوان وفعّل المفتاح.

  • يُرسَل إلى Slack وMattermost الشكل {"text": …}، وإلى Discord الشكل {"content": …} (يرفض Discord الرسائل التي تتجاوز 2000 حرف، ولذلك يُقتطَع النص)؛
  • أي عنوان آخر يستقبل JSON منظَّمًا: text وevent وseverity وsource وcount وhost وts — فلا حاجة إلى تحليل نص الرسالة من جديد.

التنبيهات الفورية. تصل الرسالة إلى المتصفح مباشرة، وإذا كانت اللوحة مضافة إلى الشاشة الرئيسية للهاتف فستظهر كإشعار تطبيق عادي — دون بوت ودون خادم بريد في المنتصف. «الإعدادات» → التنبيهات الفورية: فعّل المفتاح واضغط «وصل هذا الجهاز» على كل جهاز ينبغي أن يستقبل التنبيهات. ويبيّن عدّاد «الأجهزة المتصلة» كم عددها.

لا تعمل التنبيهات الفورية إلا عبر HTTPS (مثل WebAuthn تمامًا)، والإذن مطلوب مرتين: أولًا في المتصفح — يظهر الطلب بعد زر «وصل هذا الجهاز» — ثم في نظام التشغيل نفسه. فإذا كان المفتاح العام الإعدادات ← النظام ← الإشعارات مغلقًا في Windows، فسيمنح المتصفح الإذن وستُبلِغ اللوحة عن الإرسال، ومع ذلك لن يظهر شيء على الشاشة. والأمر نفسه يسبّبه وضع «عدم الإزعاج» وإيقاف إشعارات المتصفح في macOS (إعدادات النظام ← الإشعارات).
لكل قناة زر «إرسال اختبار» خاص بها يتحقق منها فورًا. أما جدولة التقرير التلقائي فتتم عبر cron (قسم «جميع مهام cron»): يطلق cron عملية الإرسال، وتُؤخَذ القنوات من الإعدادات.

حالة التقرير: «تنبيه» أو «سليم». يصبح العنوان «تنبيه» فقط عند وجود مشكلة فعلية أو إجراء بانتظار التنفيذ: عُثر على تهديد في ClamAV، أو تغييرات ملفات في AIDE، أو أحداث حرجة في Falco (Emergency/Alert/Critical خلال آخر 24 ساعة)، أو خدمة متوقفة في Monit، أو حاجة لإعادة التشغيل، أو قرب انتهاء SSL (≤14 يومًا)، أو تحديثات أمان بانتظار التطبيق. أما الضجيج الخلفي — محاولات SSH من البوتات، وعناوين IP المحظورة بواسطة fail2ban، وتنبيهات Suricata، وتحذيرات Lynis، وطلبات ModSecurity التي صُدَّت فعلًا — فهو لا يرفع الحالة، لذا فإن هذه الأرقام في التقرير لا تعني «تنبيه» بحد ذاتها.

07. الترخيص — الإدخال والتفعيل

تُفتح وحدات المراقبة التفصيلية (Lynis وUFW وModSecurity وخريطة الهجمات وAIDE وClamAV وغيرها) عند وجود ترخيص ساري المفعول. بدونه تعمل لوحة المعلومات والإعدادات والحساب، بينما تعرض الوحدات بطاقة «الترخيص مطلوب».

بعد الشراء في الحساب الشخصي يكون لديك رمز تفعيل بالصيغة ARCIVEO-XXXX-XXXX-XXXX-XXXX. يجب «تفعيله» على نطاق لوحتك — سيحوّل هذا الرمز إلى ملف ترخيص موقّع (الكتلة [license]) تقوم بلصقه في اللوحة.

كيفية التفعيل (٣ خطوات):

  1. احصل على رمز التفعيل. الحساب الشخصي my.arciveo.com ← قسم «التراخيص» / «تفعيل الترخيص» — انسخ الرمز ARCIVEO-….
  2. فعّل الرمز على نطاقك. في الحساب نفسه افتح «تفعيل الترخيص»، وأدخل: رمز التفعيل، وبريدك الإلكتروني، ونطاق اللوحة (العنوان الذي يُفتح به المونيتور، مثل monitor.example.com). اضغط تفعيل — سيُنشئ النظام ملف ترخيص مرتبطًا بهذا النطاق ويعرضه في حقل مع زر «نسخ».
  3. الصق المفتاح في اللوحة. انسخ نص الترخيص بالكامل ← في اللوحة افتح «الإعدادات» ← كتلة «الترخيص»، والصق ثم اضغط «حفظ». تُفتح الوحدات فورًا.

تتحقق اللوحة من المفتاح تشفيريًا: التوقيع والارتباط بالنطاق ومدة الصلاحية.

يجب أن يتطابق النطاق عند التفعيل تمامًا مع عنوان اللوحة. خذه من الثابت APP_URL في config.php وأدخل اسم المضيف فقط — بدون https:// وبدون البادئة www. التفعيل يتم مرة واحدة: يتحوّل الرمز إلى ترخيص للنطاق المُدخَل ولا يُفعَّل مجددًا — عند وجود خطأ في النطاق لن يناسب المفتاح لوحتك، وسيُستهلك الرمز. لذلك أدخل النطاق بعناية.
إذا انتهت المدة أو تغيّر النطاق — سيظهر تحذير في رأس اللوحة. الترخيص مرتبط بالنطاق نهائيًا ولا يُنقل إلى نطاق آخر: للمدة الجديدة أو النطاق الجديد يلزم مفتاح جديد (يُشترى في الحساب ويُفعَّل مرة واحدة).

08. ملف config.php — كل إعدادات اللوحة

جميع المعطيات الأساسية للوحة محددة في ملف واحد config.php في الجذر (بجوار مجلد public/) عبر ثوابت define() اعتيادية. يُنشأ الملف أثناء التثبيت؛ ونادرًا ما تحتاج إلى تعديله يدويًا — غالبًا عند تغيير الدومين أو النقل أو الاتصال بقاعدة بيانات أخرى. بعد أي تعديل أعد تشغيل PHP-FPM (وإلا فلن تُطبّق التغييرات بسبب OPcache).

ضع قيمك مكان التظليلات؛ واترك الباقي كما هو:

// --- قاعدة البيانات --- define('DB_HOST', 'localhost'); // اتركه define('DB_NAME', 'db_name'); // ما حددته عند إنشاء القاعدة define('DB_USER', 'user'); // ما حددته عند إنشاء القاعدة define('DB_PASS', 'db_password'); // ما حددته عند إنشاء القاعدة define('DB_CHARSET', 'utf8mb4'); // اتركه // --- التطبيق --- define('APP_URL', 'https://monitor.example.com'); // عنوان اللوحة، دون شرطة مائلة في النهاية define('TIMEZONE', 'Asia/Riyadh'); // منطقتك الزمنية // --- مدة الجلسة --- define('SESSION_LIFETIME', 28800); // مدة الخمول حتى إعادة الدخول، ثانية (28800 = 8 س)

قاعدة البيانات. بيانات الاتصال بـ MySQL/MariaDB:

  • DB_HOST — مضيف نظام قاعدة البيانات، وهو غالبًا localhost؛
  • DB_NAME — اسم قاعدة بيانات اللوحة؛
  • DB_USER — مستخدم القاعدة (وصول إلى قاعدته فقط)؛
  • DB_PASS — كلمة مرور هذا المستخدم؛
  • DB_CHARSET — ترميز الاتصال، اترك utf8mb4.

التطبيق.

  • APP_URL — العنوان الكامل للوحة (مثل https://monitor.example.com). يجب أن يطابق الدومين الذي فُعّلت عليه الرخصة — وإلا فسيُرفض المفتاح (انظر قسم «الرخصة»)؛
  • TIMEZONE — المنطقة الزمنية لـ PHP: تؤثر فقط على طريقة عرض اللوحة للتواريخ والأوقات. ولا تؤثر على أوقات تشغيل مهام cron — فتلك تتبع منطقة النظام (انظر «كل مهام cron»).

مدة الجلسة. SESSION_LIFETIME — مهلة خمول الجلسة بالثواني (منزلقة: تتجدد عند النشاط). القيمة الافتراضية 28800 = 8 ساعات؛ وبعد هذه المدة من الخمول تطلب اللوحة إعادة الدخول. مثلاً 3600 = ساعة واحدة، 86400 = يوم كامل.

تسجيل الأخطاء. لا تُعرض الأخطاء للزوار أبدًا، بل تُكتب في logs/php_errors.log — وتظهر في صفحة «سجلات التطبيق». هذه الأسطر (display_errors=0 وlog_errors=1 والمسار error_log) لا حاجة لتعديلها عادةً — فالإعدادات محددة داخل الملف مباشرةً ولا تعتمد على php.ini.

config.php ملف سرّي. يحتوي على كلمة مرور القاعدة. يوجد في جذر اللوحة (بجوار public/)، وجذر الويب (DocumentRoot) لهذه اللوحة هو جذر اللوحة نفسه لا public/. والملف بذاته لا «يتسرّب»: ففي .htaccess الجذري يوجد منع صريح له (Require all denied) — فيعيد السيرفر 403. وحتى بدون هذه القاعدة لما تسرّب المصدر: فهذا PHP — ينفّذه السيرفر ولا يعرضه كنص. وللاحتياط: لا تنشره في مستودعات عامة ولا ترسله للدعم بكلمة مرور حقيقية. صلاحيات الملف — 640.
عند النقل أو استعادة الوصول يكون هذا الملف المصدر الرئيسي للبيانات: اسم القاعدة والمستخدم وكلمة المرور تُؤخذ من هنا (انظر قسمي «تحديث ونقل اللوحة» و«استعادة الوصول»).

09. واجهة برمجية للقراءة فقط (JSON وPrometheus)

اللوحة محميّة بتسجيل الدخول بكلمة مرور، وبمرشِّح عناوين IP إن كان مفعّلًا. ولا يناسب البرنامجَ أيٌّ منهما، ولذلك للأنظمة الخارجية مدخل خاص بها — عنوانان للقراءة فقط محميّان برمز وصول. والرمز لا يغيّر شيئًا على الخادم: كل ما يتيحه هو جلب المؤشرات.

التفعيل — «الإعدادات» ← «واجهة برمجية للقراءة فقط»: المفتاح «تفعيل الواجهة البرمجية»؛ ويُنشَأ الرمز تلقائيًا عند أول حفظ. وزر «رمز جديد» يصدر رمزًا آخر ويقطع في اللحظة نفسها كل من كان يستعمل الرمز السابق.

  • /api/status.php — JSON: تقييم الأمان، وحالة الوحدات، وآخر قياس للحِمل مع أثقل العمليات، وأحداث الأمان خلال 24 ساعة؛
  • /api/metrics.php — الأرقام نفسها بصيغة Prometheus النصية (مقاييس arciveo_*: arciveo_security_score وarciveo_fail2ban_banned وarciveo_cpu_busy_pct وغيرها).
curl -H "Authorization: Bearer <TOKEN>" https://monitor.example.com/api/status.php curl -H "Authorization: Bearer <TOKEN>" https://monitor.example.com/api/metrics.php

وإن كان عميلك لا يستطيع ضبط ترويسة، فالرمز مقبول أيضًا كمعامل — ?token=…. ولاحظ أنه بهذه الصيغة ينتهي به المطاف في سجل وصول خادم الويب، ولذلك فالترويسة أفضل.

Prometheus. كتلة جاهزة لـ scrape_configs:

scrape_configs: - job_name: arciveo metrics_path: /api/metrics.php scheme: https authorization: credentials: <TOKEN> static_configs: - targets: ['monitor.example.com']
يُخزَّن الرد مؤقتًا 5 دقائق: فخلف هذه الأرقام عملية الجمع الثقيلة نفسها التي تقف خلف لوحة المعلومات. ولذلك لا يكلّف الاستعلام المتكرر الخادمَ شيئًا — إذ تتكرر القيم ببساطة حتى التحديث التالي — كما أن فاصلًا أقل من دقيقة لا معنى له أيضًا.
401 — الرمز خاطئ أو لم يُرسَل. و404 مع النص api disabled — الواجهة البرمجية معطّلة في الإعدادات. وتُكتَب الطلبات المرفوضة في سجل التطبيق مع عنوان IP للمرسِل، فتظهر محاولات تخمين الرمز في صفحة «سجلات التطبيق».

10. ملخص الخوادم في الحساب الشخصي

تُثبَّت اللوحة على كل خادم على حدة، وهي تجيب جيدًا عن سؤال «كيف حال هذا الجهاز». أما سؤال «كيف حال أجهزتي كلها» فلا تجيب عنه — ولهذا تستطيع كل لوحة أن ترسل ملخصًا قصيرًا إلى الحساب الشخصي، حيث تظهر الخوادم في قائمة واحدة.

ما تأخذه من الحساب الشخصي my.arciveo.com ← قسم «خوادمي»: يُصدَر هناك رمز (بالشكل fk_…) ويُذكَر عنوان المستقبِل https://my.arciveo.com/api/fleet.php. والرمز واحد لكل حساب — هو نفسه لجميع خوادمك.

ما تضبطه في اللوحة — «الإعدادات» ← «ملخص الخوادم»: عنوان المستقبِل، والرمز، واسم الخادم (كما سيظهر في القائمة؛ وإن تركته فارغًا أُخِذ نطاق اللوحة)، ومفتاح «إرسال الملخص». وزر «أرسل الآن» يتحقق من الاتصال في الحال دون انتظار الجدولة.

وبعد ذلك يذهب الملخص عبر cron كل 15 دقيقة:

# كل 15 دقيقة — ملخص الخادم إلى الحساب الشخصي 3,18,33,48 * * * * /usr/local/bin/fleet-push-all.sh >> /path/to/monitor/logs/cron.log 2>&1

ما الذي يُرسَل بالضبط: اسم الخادم ونطاقه، ونظام التشغيل، ومدة التشغيل، وإصدار PHP؛ وتقييم الأمان؛ وحالة الوحدات (UFW، وعدد سجون Fail2ban، وعمليات الحظر اليوم، وهل تعمل CrowdSec وSuricata وFalco، وتهديدات ClamAV، وتغيّرات AIDE، ومؤشر Lynis، والتحديثات المنتظِرة، وهل تلزم إعادة تشغيل، وكم يومًا بقي على انتهاء الشهادة، وعدد المنافذ المفتوحة الخطرة)؛ وآخر قياس للحِمل (load والمعالج والذاكرة والقرص وinodes)؛ وعدّادات الأحداث خلال 24 ساعة وآخر حدث حرج. وليس في الملخص سجلات ولا كلمات مرور ولا محتويات ملفات.

الخادم هو الذي يرسل، والحساب لا يسأل. ولهذا لا حاجة إلى فتح أي مدخل إلى شبكتك من الخارج، واللوحة المغلقة بمرشِّح IP تُبلِّغ أيضًا. ويُعرَف الخادم من نطاق اللوحة، فلا تتضاعف القائمة بعد إعادة التشغيل أو تغيير عنوان IP.
وإذا ظهر خادم في الحساب موسومًا بأنه صامت فمعنى ذلك أن الملخص لم يصل منذ مدة. تحقّق بالترتيب: مفتاح «إرسال الملخص»، وسطر cron (sudo crontab -l)، وماذا يردّ زر «أرسل الآن». وتُكتَب أخطاء الإرسال في سجل التطبيق بعلامة FLEET — وهناك يتبيّن هل رُفض الرمز (HTTP 401) أم أن الاتصال نفسه لم يتم.

أدوات الأمان

11. جدار الحماية UFW

UFW (Uncomplicated Firewall) — واجهة بسيطة لـ nftables/iptables. يغلق كل المنافذ الواردة عدا المسموح بها صراحةً. صفحة «جدار الحماية UFW» تعرض الحالة والقواعد.

sudo apt install ufw # السماح بـ SSH (إلزامي قبل التفعيل!) والويب sudo ufw allow OpenSSH sudo ufw allow 80,443/tcp # إغلاق قاعدة البيانات من الخارج (الوصول محليًا فقط) sudo ufw deny 3306 # التفعيل والتحقق sudo ufw enable sudo ufw status verbose
قبل ufw enable اسمح بـ SSH إلزاميًا (ufw allow OpenSSH)، وإلا ستفقد الوصول إلى السيرفر.
يأخذ «الانكشاف الخارجي» في لوحة التحكم UFW بالحسبان: المنفذ المغلق بقاعدة deny لا يُعتبر متاحًا من الخارج.
Skipping adding existing rule — ليس خطأً. بهذا يُبلغ UFW أن قاعدة مطابقة تمامًا موجودة بالفعل ولا يضيفها مجددًا. عند إعادة تشغيل الإعداد التلقائي (وهو عملية عديمة التأثير التراكمي) تكون هذه رسالة اعتيادية — لا حاجة للتدخل.

12. تثبيت Fail2ban

يحظر عنوان IP تلقائياً بعد تجاوز عدد محاولات الدخول الفاشلة. يحلّل سجلّات SSH وnginx وApache وخدمات أخرى.

sudo apt install fail2ban sudo systemctl enable --now fail2ban # التحقق من الحالة: sudo fail2ban-client status
إعداد عملي (jail.local مع عشرات jail والحظر التلقائي من ipsum) — في القسم التالي.

13. إعداد عملي لـ Fail2ban + ipsum

التثبيت الأساسي مذكور أعلاه. هنا إعداد عملي يوفّر عشرات الـ jail النشطة وآلاف الحظر: الإعدادات العامة، وأهم الـ jail، والحظر التلقائي للـ IP الخبيثة من قائمة ipsum.

الملف /etc/fail2ban/jail.local — الإعدادات العامة وأهم الـ jail:

[DEFAULT] bantime = 1w findtime = 900 maxretry = 3 backend = systemd banaction = nftables-multiport ignoreip = 127.0.0.1/8 ::1 <YOUR_IP> <TRUSTED_NETS> # حظر تصاعدي: كل تكرار يزيد المدة bantime.increment = true bantime.factor = 2 bantime.maxtime = 5w bantime.rndtime = 300 [sshd] enabled = true maxretry = 5 bantime = -1 # حظر دائم لهجمات القوة الغاشمة على SSH findtime = 3600 # المعاودون: من تلقّى عدة عمليات حظر يُحظر نهائيًا [recidive] enabled = true logpath = /var/log/fail2ban.log banaction = %(banaction_allports)s bantime = -1 findtime = 86400 maxretry = 2 [http-get-dos] enabled = true maxretry = 100 findtime = 300 bantime = 1w # خدمات الويب (apache-*, nginx-*, php-url-fopen, phpmyadmin-syslog): [nginx-http-auth] enabled = true port = http,https [apache-badbots] enabled = true port = http,https # … وبقية الـ jail حسب الخدمات (dovecot, exim, postfix-sasl, # mysqld-auth, vsftpd, portscan, pam-generic) — enabled = true
في ignoreip اكتب حتمًا عنوان IP الخاص بك والشبكات الموثوقة، وإلا فقد تحظر نفسك. بعد التعديلات: sudo fail2ban-client reload.

التحميل التلقائي لقائمة الحظر ipsum — في cron الخاص بـ root (sudo crontab -e): يُحمَّل level 1 (أكثر من 100 ألف IP) إلى المجموعة ipsum التي تُحظر على جدار الحماية (التفاصيل في قسم «قائمة الحظر IPset»):

# 04:00 — تحديث ipset ipsum (level 1، أوسع تغطية): 0 4 * * * /usr/local/bin/load-ipsum.sh >> /path/to/monitor/logs/cron.log 2>&1
يجب أن تُسمّى المجموعة ipsum — فهي التي تقرأها لوحة التحكم (بطاقة «IPset ipsum»). المستويات: levels/1.txt — أوسع تغطية، levels/3.txt — أدق (3 مصادر أو أكثر).

لماذا يُقسَّم «مراقب الأمان» إلى منطقتين. تعمل الحماية على مستويين، ولوحة التحكم لا تخلط بينهما:

  • الهجمات الحقيقية (تفاعلية) — كل ما التقطه fail2ban: محاولات اختراق فعلية (jail مثل sshd وapache-* وnginx-* وغيرها) والمعاودون الخطرون (jail recidive — من سبق حظرهم عدة مرات). هذه عناوين IP اقتحمتك فعلًا — وهي على خريطة الهجمات و«الخط الزمني».
  • الحظر الوقائي (استباقي) — قائمة الحظر العامة لعناوين IP الخبيثة المعروفة ipset ipsum، تُحظر على جدار الحماية بقاعدة DROP. معظم هذه العناوين لم تمسّ سيرفرك أصلًا — تُقطع مسبقًا؛ ويُظهر عدّاد «IPset ipsum» كم عنوانًا قُطع وقائيًا.

الفرق بسيط: التفاعلي — «هؤلاء هاجموا وحُظروا»، والوقائي — «هؤلاء حُظروا قبل المحاولة». سابقًا كان list-3 ipsum يُحشر في recidive بشكل مصطنع (ومن هنا جاء التقسيم القديم «recidive القائمة»)؛ أما الآن فـ recidive للمعاودين الحقيقيين فقط، والوقائي كله على جدار الحماية.

14. قائمة الحظر IPset (ipsum)

ipsum — قائمة عامة بعناوين IP الخبيثة تُحدَّث يوميًا. يعرض المونيتور عدد العناوين المحمّلة على لوحة المعلومات وخريطة الهجمات ويأخذه بالحسبان في تقييم الأمان (−10 إذا لم تُحمَّل المجموعة).

الخيار الأدنى بدون fail2ban — مجموعة ipsum منفصلة مع الحظر عبر iptables:

# إنشاء المجموعة (مرة واحدة): sudo ipset create ipsum hash:ip # سكربت التحديث /usr/local/bin/update-ipsum.sh: #!/bin/bash ipset flush ipsum for ip in $(curl -s https://raw.githubusercontent.com/stamparm/ipsum/master/levels/3.txt); do ipset add ipsum "$ip" 2>/dev/null done iptables -C INPUT -m set --match-set ipsum src -j DROP 2>/dev/null \ || iptables -I INPUT -m set --match-set ipsum src -j DROP # Cron (sudo crontab -e، يوميًا الساعة 4:00): 0 4 * * * /usr/local/bin/update-ipsum.sh
الخيار الموسّع مع fail2ban-recidive — في قسم «إعداد عملي لـ Fail2ban + ipsum».
ipset يعيش في الذاكرة ويُفقد عند إعادة التشغيل. اعتمادُ الكرون اليومي وحده يترك المجموعة فارغة من لحظة الإقلاع حتى التشغيل التالي (تعرض لوحة المعلومات 0). حمِّل المجموعة أيضًا عند الإقلاع — انقل التحميل إلى سكربت واربطه بـ @reboot. وبالمناسبة، الأمر create … -exist يضبط الحد maxelem 300000 (الافتراضي 65536 — لا تتّسع له level 1 وسيظهر «Hash is full»):
# /usr/local/bin/load-ipsum.sh #!/bin/bash curl -s https://raw.githubusercontent.com/stamparm/ipsum/master/levels/1.txt \ | grep -v '^#' | sed 's/^/add ipsum /' \ | (echo "create ipsum hash:ip hashsize 131072 maxelem 300000 -exist"; echo "flush ipsum"; cat) \ | ipset restore -exist # sudo crontab -e — يوميًا الساعة 04:00 وعند كل إقلاع: 0 4 * * * /usr/local/bin/load-ipsum.sh @reboot sleep 60 && /usr/local/bin/load-ipsum.sh
كيف يعمل الأمر عند التثبيت التلقائي. يحمّل السكربت قائمة level 1 الكاملة (أكثر من 100 ألف IP) إلى مجموعة ipsum، وإذا كان المثبِّت هو من يدير جدار الحماية (VPS جديد — الملفان «الكامل»/«المخفّف»)، فإنه يربط المجموعة بـ UFW عبر قاعدة DROP — فيُحظر فعليًا المرور من هذه العناوين. تأتي القاعدة بعد ESTABLISHED,RELATED، لذا لا تنقطع الاتصالات الحالية (بما فيها SSH الخاص بك) — تُقطع فقط الاتصالات الجديدة من القائمة. تُستعاد المجموعة عند تحميل الخدمة ipsum-load.service قبل جدار الحماية (وإلا لما عمل UFW)، وتُحدَّث بالكرون الساعة 04:00. على سيرفر مُعدّ مسبقًا (لوحة تحكم، جدار حماية خاص) لا يتدخل المثبِّت في جدار الحماية — هناك يبقى ipsum قائمةً للوحة المعلومات وخريطة الهجمات، وتُضاف قاعدة DROP يدويًا عند الرغبة (الخيار الأدنى مع iptables … --match-set ipsum … -j DROP — أعلاه). عند التثبيت التلقائي لا حاجة لفعل أي شيء يدويًا.

15. تثبيت CrowdSec

بديل حديث لـ Fail2ban مع threat intelligence جماعي: حظر من المجتمع بالإضافة إلى قواعدك الخاصة. يتطلب bouncer منفصلاً لتطبيق الحظر على الجدار الناري.

curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash sudo apt install crowdsec sudo systemctl enable --now crowdsec # Bouncer لـ iptables/nftables: sudo apt install crowdsec-firewall-bouncer-iptables # التحقق من الحالة: sudo systemctl status crowdsec sudo cscli decisions list sudo cscli bouncers list
الحالة «غير مُشغَّل» في اللوحة = الحزمة مثبّتة لكن الخدمة غير نشطة (يتحقق المونيتور منها عبر systemctl is-active crowdsec). للتشغيل: sudo systemctl enable --now crowdsec؛ وعند التعطّل راجع sudo journalctl -u crowdsec -n 30. تنطبق القاعدة نفسها على أي خدمة بحالة «غير مُشغَّل» (Suricata، Falco، Monit، MySQL).
«0 سيناريو» أو «0 bouncers» في لوحة التحكم. يأتي CrowdSec افتراضياً فارغاً تقريباً — فبدون المجموعات لا يكتشف شيئاً، وبدون bouncer مُسجَّل لا يُطبَّق الحظر على الجدار الناري. ثبّت المجموعات الأساسية وتأكد من وجود الـ bouncer في القائمة:
# المجموعات الأساسية (Linux + SSH + سيرفر الويب): sudo cscli collections install crowdsecurity/linux crowdsecurity/sshd crowdsecurity/base-http-scenarios sudo systemctl reload crowdsec # يجب أن يكون الـ bouncer في القائمة وبحالة اتصال نشط: sudo cscli bouncers list
في سجلّ الـ bouncer stream halted / الحظر لا يُطبَّق. هذا مفتاح api يتيم: أُزيل الـ bouncer من cscli bouncers list لكن مفتاحه القديم بقي في /etc/crowdsec/bouncers/*.yaml. أعد تسجيل الـ bouncer واكتب المفتاح الجديد:
sudo cscli bouncers add fw-bouncer # سيُخرج api_key جديداً # اكتب هذا المفتاح في api_key: داخل /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml sudo systemctl restart crowdsec-firewall-bouncer
التثبيت التلقائي (ملف «الحماية الكاملة») يثبّت المجموعات ويسجّل firewall-bouncer بنفسه — ولا حاجة لفعل ذلك يدوياً إلا عند التثبيت اليدوي أو بعد تدخّل يدوي في CrowdSec.

16. تثبيت AIDE

AIDE (Advanced Intrusion Detection Environment) يأخذ لقطة لنظام الملفات ويُبلغ في كل فحص عن التغييرات في /etc و/bin و/usr. بعد التثبيت لا بد من تهيئة قاعدة البيانات (aideinit).

sudo apt install aide # تهيئة قاعدة البيانات (5–15 دقيقة): sudo aideinit sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db # Ubuntu 24.04: يُنشأ الدليل /var/lib/aide بصلاحية 700 (المالك _aide)، # ولا تراه اللوحة (www-data) → تعرض «غير مُهيّأة». # افتح الدليل للمرور (تبقى ملفات القاعدة بصلاحية 600): sudo chmod 755 /var/lib/aide # أول فحص مع الكتابة في السجل الذي يقرأه المونيتور. # على Ubuntu/Debian يتطلب aide تمرير ‎--config‎ صراحةً (وإلا «missing configuration»؛ # ولا يُشحن الملف التنفيذي aide.wrapper في الإصدارات الجديدة): sudo bash -c 'aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1'
أثناء aideinit يظل الطرفية عالقة على السطر Running aide --init... لمدة 5–15 دقيقة — وهذا طبيعي (تجزئة نظام الملفات كاملاً، حِمل على القرص). لا تقاطعه بـ Ctrl+C. إذا بدا العملية «معلّقة» دون كتابة أي شيء — فقد تكون تنتظر الرد على طلب مخفي Overwrite existing aide.db.new [Yn]? (اضغط Y). للتحقق من النشاط من جلسة أخرى: pgrep -af aide.
خطأ aideinit: «21_aide_spamassassin … printf: invalid number» (return code 20) — علة معروفة في مقتطف إعدادات AIDE على Ubuntu 22.04. لا تُنشأ القاعدة. أخرِج المقتطف المعطوب وأعِد المحاولة:
sudo mv /etc/aide/aide.conf.d/21_aide_spamassassin /etc/aide/21_aide_spamassassin.disabled sudo aideinit sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
الحالات على لوحة المعلومات. «غير مُهيّأة» = اللوحة لا ترى ملف القاعدة: إما أن aideinit لم يُشغَّل، أو (Ubuntu 24.04) أن الدليل /var/lib/aide أُنشئ بصلاحية 700 ولا يصل إليه www-data — ويُعالَج بـ sudo chmod 755 /var/lib/aide (انظر الكتلة أعلاه). «لم يُجرَ أي فحص» = القاعدة موجودة لكن لم يُنفَّذ فحص بعد — وهذا ليس خطأً. يقرأ المونيتور النتائج من /var/log/aide/aide.log.
الفحص الدوري ← سجل للّوحة. قد لا يكتب /etc/cron.daily/aide القياسي على Ubuntu/Debian الحديثة ملف /var/log/aide/aide.log بالشكل المطلوب (كما أن aide.wrapper لم يعد موجوداً فيها). الأوثق إضافة كرون خاص بك مع --config صريح — فهو يكتب السجل من root بصلاحية 644، ويقرأه المونيتور دون مجموعات إضافية:
# sudo crontab -e — فحص يومي في 02:00: 0 2 * * * /usr/bin/aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1 # شغّله الآن دون انتظار الجدولة: sudo bash -c 'aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1'
التثبيت التلقائي يقوم بكل هذا مسبقاً: chmod 755 /var/lib/aide وكرون فحص في 02:00 — لا حاجة لأي شيء يدوياً.
نفّذ التهيئة الأولى على سيرفر نظيف — قبل تثبيت تطبيقات الويب. وبعد التغييرات المشروعة أعِد إنشاء القاعدة: sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db.

17. تثبيت ClamAV

ماسح مضاد للفيروسات لنظام Linux. مفيد بشكل خاص لفحص /var/www بحثًا عن أصداف PHP والشيفرات الخبيثة.

sudo apt install clamav clamav-daemon sudo systemctl enable --now clamav-daemon # تحديث قاعدة التواقيع: sudo freshclam # فحص مجلد يدويًا: sudo clamscan -r /var/www --infected
الخدمة clamd تُظهر «غير نشطة» بعد enable --now؟ ثلاثة أسباب شائعة:

1. بقي السطر Example في ملف الإعداد — يرفض clamd الإقلاع طالما كان موجودًا:

sudo sed -i '/^Example/d' /etc/clamav/clamd.conf sudo systemctl restart clamav-daemon

2. لم يتم تنزيل قاعدة التواقيع — لا يُقلع clamd بدونها:

sudo systemctl stop clamav-freshclam sudo freshclam sudo systemctl start clamav-freshclam sudo systemctl restart clamav-daemon

3. إنه يُحمّل فقط — يُحمّل clamd نحو 8 ملايين توقيع في الذاكرة خلال 30–60 ثانية. انتظر وتحقق: systemctl is-active clamav-daemon (الحالة activating ← ما زال يُحمّل).

التشخيص: sudo journalctl -u clamav-daemon -n 30 --no-pager.
على لوحة التحكم «الملفات المفحوصة: 0» / «آخر فحص: —»؟ الخدمة clamd تُبقي التواقيع في الذاكرة فقط، وهي بذاتها لا تفحص أي شيء وفق جدول زمني. تعرض اللوحة نتائج الفحص المجدول، لذا يلزم مهمة cron تفحص وتكتب سجلًا. يثبّت التثبيت التلقائي الغلاف /usr/local/bin/clamav-scan.sh ومهمة cron في 01:30 — بعد التشغيل الأول تُملأ «الملفات المفحوصة» و«آخر فحص». للتشغيل فورًا دون انتظار الجدول: sudo /usr/local/bin/clamav-scan.sh.

18. تثبيت Linux Malware Detect (maldet)

Linux Malware Detect (LMD) — أداة فحص للبرمجيات الخبيثة الموجّهة لتهديدات الويب: أصداف PHP والأبواب الخلفية للويب والمُحمّلات. يستخدم محرك ClamAV ويكمّله بتواقيعه الخاصة.

wget https://www.rfxn.com/downloads/maldetect-current.tar.gz tar -xzf maldetect-current.tar.gz dir=$(ls -d maldetect-*/ | head -1) && cd "$dir" && sudo bash install.sh && cd ~ rm -rf maldetect-* maldetect-current.tar.gz # تحديث التواقيع: sudo maldet -u # فحص /var/www: sudo maldet -a /var/www
يعمل LMD وClamAV معاً بشكل جيد. آخر تقرير: maldet --report.
قد يظهر أثناء التثبيت السطر update-rc.d: error: unable to read /etc/init.d/maldet — وهو غير ضار. لا يستخدم maldet آلية init.d، إذ يتم تشغيل تحديث التواقيع والفحوصات عبر /etc/cron.daily/maldet. إذا ظهر أدناه installation completed فقد اكتمل التثبيت.
هل تظهر الصفحة أن LMD «غير مثبّت» رغم تثبيته؟ لا يُثبّت maldet عبر apt بل في /usr/local/maldetect، وعند تفعيل open_basedir يُتحقق من وجوده عبر shell — راجع قسم «الصفحة فارغة رغم وجود البيانات على السيرفر».

19. تثبيت Suricata

نظام شبكي لكشف التسلل: يحلل حركة المرور على مستوى الحزم ويعرف آلاف توقيعات الهجمات. يكمّل ModSecurity (الذي يعمل على مستوى HTTP، بينما تعمل Suricata على مستوى TCP/IP).

sudo add-apt-repository ppa:oisf/suricata-stable sudo apt update && sudo apt install suricata # تنزيل القواعد الحالية: sudo suricata-update sudo systemctl enable --now suricata
Suricata في حالة «نشط» لكن اللوحة لا تعرض تنبيهات / عدد الأحداث 0؟ تكتب Suricata في /var/log/suricata/eve.json تحت root بصلاحية 750 على المجلد، ولا يستطيع سيرفر الويب (www-data) قراءته. افتح المجلد للمرور — تبقى الملفات بداخله محمية:
sudo chmod o+rx /var/log/suricata
التثبيت التلقائي يقوم بذلك بنفسه — لا حاجة لفعله يدويًا.

20. تثبيت Falco

يعترض استدعاءات النظام عبر eBPF/kernel module ويكتشف الحالات الشاذة في الوقت الفعلي: تشغيل shell من nginx، قراءة عملية الويب لـ /etc/passwd، الكتابة في /bin وما إلى ذلك.

curl -fsSL https://falco.org/repo/falcosecurity-packages.asc > /tmp/falco.asc gpg --dearmor < /tmp/falco.asc | sudo tee /usr/share/keyrings/falco-archive-keyring.gpg > /dev/null sudo chmod 644 /usr/share/keyrings/falco-archive-keyring.gpg && rm /tmp/falco.asc echo "deb [signed-by=/usr/share/keyrings/falco-archive-keyring.gpg] https://download.falco.org/packages/deb stable main" \ | sudo tee /etc/apt/sources.list.d/falcosecurity.list sudo apt update && sudo apt install falco sudo systemctl enable --now falco
يقرأ المونيتور أحداث Falco عبر journalctl -u falco (دون sudo — عبر مجموعة systemd-journal). تأكد من أن www-data ضمن هذه المجموعة — راجع «إعداد sudo» (البند 2) في صفحة التثبيت اليدوي.
«0 حدث خلال 24 ساعة» أمر طبيعي وليس خطأً. يعمل Falco بنمط event-driven: يبقى صامتاً ما دام كل شيء على ما يرام، ويسجّل حدثاً فقط عند وجود حالة شاذة (shell من عملية ويب، قراءة /etc/passwd، الكتابة في أدلة النظام). صفر أحداث حرجة خلال اليوم على سيرفر هادئ يعني حالة صحية.
الإخراج إلى ملف أكثر موثوقية للوحة التحكم. تتطلب القراءة عبر journalctl صلاحيات على السجل؛ ولكي ترى اللوحة الأحداث بثبات، يفعّل التثبيت التلقائي في Falco خاصية file_output ← /var/log/falco/falco.log ويضبط للخدمة UMask=0022 (يمكن لسيرفر الويب قراءة السجل). لا حاجة لضبط ذلك يدوياً على تثبيت جديد.

21. تثبيت ModSecurity (WAF)

ModSecurity — جدار حماية للويب (WAF) لـ Apache أو Nginx. يحجب الهجمات على مستوى التطبيق: حقن SQL، وXSS، وتجاوز المسارات، والماسحات.

# Apache: sudo apt install libapache2-mod-security2 sudo a2enmod security2 # مجموعة قواعد OWASP Core Rule Set: sudo apt install modsecurity-crs # إلزامي: بدون هذا الملف يكون محرك القواعد معطلاً sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf sudo sed -i 's/^SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf sudo apache2ctl configtest && sudo systemctl reload apache2 # التحقق: يجب أن يُرجع 403 curl -s -o /dev/null -w '%{http_code}\n' "https://monitor.example.com/?id=1%20UNION%20SELECT%201,2--"
تثبيت الحزمة وحده لا يوفّر أي حماية. يُحمّل Apache ملفات الإعداد بالسطر IncludeOptional /etc/modsecurity/*.conf، بينما تضع الحزمة فقط modsecurity.conf-recommended — وهو لا يطابق النمط *.conf. إن لم تنسخه إلى modsecurity.conf، يبقى SecRuleEngine على Off: الوحدة محمّلة، وقواعد CRS محمّلة، لكن لا يُفحص أي مرور ولا يُنشأ سجل التدقيق. أما الوضع الوسيط DetectionOnly فيسجّل الأحداث فقط دون حجب الطلبات — وتعرضه اللوحة بالأصفر.

وصول اللوحة إلى سجل التدقيق. السجل /var/log/apache2/modsec_audit.log ملك لـ root (الصلاحيات 640)، ولا يستطيع مستخدم الويب قراءته. تأخذ اللوحة البيانات عبر غلاف — أنشئه:

sudo tee /usr/local/bin/monitor-modsec >/dev/null <<'EOF' #!/bin/sh echo "ENGINE=$(grep -hE '^SecRuleEngine[[:space:]]+' /etc/modsecurity/*.conf 2>/dev/null | tail -1 | awk '{print $2}')" echo "---LOG---" tail -n 3000 /var/log/apache2/modsec_audit.log 2>/dev/null echo "---RULES---" for f in /etc/modsecurity/crs/rules/*.conf /usr/share/modsecurity-crs/rules/*.conf /etc/modsecurity/custom-rules.conf; do [ -f "$f" ] && { echo "===FILE:$(basename "$f")==="; cat "$f"; } done EOF sudo chown root:root /usr/local/bin/monitor-modsec sudo chmod 755 /usr/local/bin/monitor-modsec # في /etc/sudoers.d/monitor (المستخدم = الذي يعمل تحته PHP-FPM): # www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-modsec
يأخذ الغلاف آخر توجيه SecRuleEngine بدون مسافة بادئة: فالأسطر ذات المسافة البادئة تقع داخل كتل <LocationMatch>/<Directory> (مثل تعطيل WAF لـ phpMyAdmin) ولا تحدد الوضع العام.
يجب أن يطابق المستخدم في sudoers مستخدم تجمّع FPM: على Apache/Debian الاعتيادي يكون www-data، وفي HestiaCP يعمل تجمّع الموقع تحت مالك الموقع (مثلاً admin) — تحقّق بـ grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.conf.
إذا كان الموقع خلف بروكسي Nginx (HestiaCP)، يرى Apache البروكسي نفسه كعميل — فتأخذ اللوحة IP المهاجم الحقيقي من ترويسة X-Forwarded-For. لا يدخل في الإحصاءات إلا المعاملات التي انطبقت عليها قاعدة: فالتوجيه SecAuditLogRelevantStatus يكتب في سجل التدقيق أي استجابات 4xx/5xx، ولذلك تدخل فيه أيضاً استجابات 403/500 العادية — واللوحة لا تعتبرها أحداث WAF.
يلزم قسمَ «كل القواعد الفعّالة» كتلةُ ---RULES--- — فاللوحة تعرض ليس فقط القواعد التي انطبقت، بل كل قواعد CRS المحمّلة والقواعد المخصّصة. المسارات الثلاثة في حلقة for f in … هي المواضع النمطية لقواعد CRS والإضافات المحلية؛ فإن كان لديك تخطيط مختلف (الحزمة تضع الملفات في مجلدها، أو القواعد المخصّصة ليست في /etc/modsecurity/custom-rules.conf)، فابحث عن المسارات الفعلية بالأمر sudo grep -rl 'IncludeOptional\|^Include ' /etc/apache2/mods-enabled/security2.conf /etc/apache2/conf-enabled/*.conf 2>/dev/null وأدرجها في القائمة. أما إذا كان الغلاف قديماً (بلا هذا القسم) — فسيعرض القسم تحذير «غير متاح» فقط، وبقية الصفحة تعمل كالسابق.

22. تثبيت Auditd

Auditd (Linux Audit Daemon) يسجّل استدعاءات النظام على مستوى النواة: تسجيلات الدخول والخروج، وأوامر sudo، ومحاولات المصادقة الفاشلة، وتغييرات الملفات. يعرض المونيتور تسجيلات الدخول والمحاولات الفاشلة وأوامر sudo لليوم.

sudo apt install auditd audispd-plugins sudo systemctl enable --now auditd # التحقق من الحالة والأحداث: sudo systemctl status auditd sudo ausearch -m USER_LOGIN -ts today
يقرأ المونيتور الأحداث عبر ausearch (/usr/sbin/ausearch) وعند الحاجة من /var/log/audit/audit.log بأمر tail. يجب أن يكون كلاهما في sudoers.

23. تثبيت Monit

يراقب الخدمات (nginx و php-fpm و mysql وغيرها) ويعيد تشغيلها عند تعطّلها. ويمكنه إرسال تنبيهات عبر البريد الإلكتروني.

sudo apt install monit sudo systemctl enable --now monit # ملفات الإعداد: sudo nano /etc/monit/monitrc ls /etc/monit/conf.d/
يحصل المونيتور على قائمة الخدمات عبر monit status. يجب تفعيل واجهة HTTP في /etc/monit/monitrc (كتلة set httpd مع allow localhost)، وإلا فسيُرجع monit status خطأً.
هل تظهر «0 خدمات تحت المراقبة» في لوحة التحكم؟ لذلك سببان. (1) واجهة HTTP معطّلة — سطر set httpd في monitrc معلّق (يأتي افتراضيًا هكذا: # set httpd port 2812 …). أزِل التعليق عن الكتلة واسمح لـ localhost. (2) تفعيل httpd وحده لا يراقب شيئًا — إذ لا يحسب Monit سوى ما يُوصف بكتل check؛ وبدونها تبقى القائمة فارغة حتى مع عمل الواجهة. أدنى إعداد فعّال:
# /etc/monit/conf.d/00-httpd — واجهة HTTP لـ localhost: set httpd port 2812 use address localhost allow localhost # أمثلة على كتل check (ما يُراقَب): check process sshd with pidfile /run/sshd.pid start program = "/usr/bin/systemctl start ssh" stop program = "/usr/bin/systemctl stop ssh" check filesystem rootfs with path / if space usage > 90% then alert
sudo monit -t # فحص الصياغة (Control file syntax OK) sudo systemctl reload monit sudo monit status
يضع التثبيت التلقائي ملف conf.d جاهزًا مع httpd على المنفذ 2812 ومجموعة من الفحوصات — لا حاجة للإعداد اليدوي على تثبيت جديد.
هل الخدمة في حالة «بها أخطاء»؟ يعرض المونيتور الحالة فقط ولا يعيد تشغيل الخدمات من لوحة الويب عمدًا (فذلك يعني تنفيذ أوامر root عن بُعد في لوحة أمان). التشخيص وإعادة التشغيل يتمّان عبر SSH من خلال Monit:
sudo monit status <service> # سبب الخطأ sudo monit restart <service> # إعادة التشغيل عبر Monit # إذا لم يشغّل Monit الخدمة — راجع الوحدة الخاصة بها: sudo systemctl status <unit> --no-pager sudo journalctl -u <unit> -n 50 --no-pager

24. تثبيت PSAD (كشف فحص المنافذ)

PSAD يحلّل سجل iptables ويكشف فحص المنافذ والهجمات الشبكية، ويسند لكل مصدر مستوى خطورة (1–5). يكمّل fail2ban وSuricata.

sudo apt install psad # يقرأ PSAD سجل iptables — يجب تفعيل التسجيل (UFW يفعله تلقائيًا). # لـ iptables النقي أضف قواعد LOG إلى سلاسل INPUT/FORWARD. sudo psad --sig-update sudo systemctl enable --now psad
يقرأ المونيتور البيانات عبر psad --Status (مطلوب في sudoers). بدون تسجيل iptables ستكون الصفحة فارغة — وهذا طبيعي ما لم تحدث عمليات فحص.

25. AppArmor / SELinux (التحكم في الوصول)

Mandatory Access Control يقيّد الملفات والموارد التي يمكن لأي برنامج الوصول إليها، حتى لو تم اختراقه. في Ubuntu/Debian يُستخدم AppArmor افتراضيًا (وغالبًا ما يكون مثبتًا ونشطًا بالفعل).

# AppArmor (Ubuntu/Debian): sudo apt install apparmor apparmor-utils sudo systemctl enable --now apparmor sudo aa-status # فحص الملفات التعريفية
يقرأ المونيتور الحالة عبر aa-status (يجب إضافته إلى sudoers). يعرض عدد الملفات التعريفية في وضع enforce/complain والعمليات بدون ملف تعريفي.

أن يكون «عدد الملفات التعريفية المحمّلة» أكبر من enforce + complain أمر طبيعي. في AppArmor 4.x (Ubuntu 24.04 وأحدث) ظهر وضع unconfined: الملف التعريفي محمّل في النواة لكنه لا يقيّد شيئًا. تضع Ubuntu هذا الوضع على عشرات الملفات التعريفية للبرامج التي تستخدم user namespaces (المتصفحات وعملاء التورنت وما شابه). عند وجود مثل هذه الملفات، تصبح بطاقة «عدد الملفات التعريفية المحمّلة» كهرمانية وتعرض عددها — مثلًا unconfined: 90 مع 120 محمّلًا و26 في enforce. الحماية الفعلية تأتي فقط من الملفات في وضع enforce؛ أما على Ubuntu 22.04 (AppArmor 3.x) فلا يوجد هذا الوضع وتتطابق الأرقام دائمًا.

sudo aa-status | grep -E "profiles are" # التفصيل حسب الوضع sudo aa-enforce /etc/apparmor.d/profile-name # نقل الملف التعريفي إلى enforce
نقل الملفات التي تركتها Ubuntu عمدًا في unconfined إلى enforce يجب أن يتم بوعي فقط: فهي معطّلة ليس عن خطأ، بل لأن تفعيلها يعطّل عمل البرامج نفسها. أما الملفات في وضع complain فأمرها مختلف: قواعدها مكتوبة بالفعل ولكنها غير مطبَّقة فحسب.

26. تثبيت debsums (سلامة الحزم)

debsums يتحقق من أن ملفات الحزم المثبّتة تطابق المجاميع الاختبارية من المستودع — يكشف الملفات الثنائية النظامية المستبدلة (يكمّل AIDE). يستغرق الفحص الكامل 1–2 دقيقة، لذا يُشغَّل عبر cron، وتقرأ اللوحة النتيجة من data/debsums/debsums.log وتصنّفها بنفسها (يهمّ فقط الملفات الثنائية والمكتبات).

المهمة تُضاف إلى كرون الجذر (sudo crontab -e). يُوضَع الغلاف الجاهز debsums-scan.sh في /usr/local/bin/ (chmod +x؛ راجع ملخص مهام cron) ويكتب التقرير بنفسه في data/debsums/ باللوحة.

sudo apt install debsums # سطر Cron (يوميًا 4:30): 30 4 * * * /usr/local/bin/debsums-scan.sh >> /path/to/monitor/logs/cron.log 2>&1

الغلاف debsums-scan.sh يجد data/ باللوحة بنفسه — لا حاجة لكتابة المسار.

التغييرات في /etc/ (ملفات الإعداد) و/usr/share/ (الموارد) على السيرفر عادةً طبيعية — تميّزها اللوحة بلون منفصل. المقلق هو تغييرات الملفات الثنائية والمكتبات (/bin، /sbin، /usr/lib وما شابه) — بطاقة «الملفات الثنائية / المكتبات» تعرض هذه تحديدًا.

27. إعداد تقارير Lynis

يُشغَّل Lynis يدويًا أو عبر cron. يجب حفظ التقرير في مجلد المشروع data/lynis/ — يقرأ المونيتور الملف lynis-report.dat.

# تشغيل لمرة واحدة (ضع مسار جذر لوحتك): sudo lynis audit system --report-file /path/to/monitor/data/lynis/lynis-report.dat # تدقيق يومي — سطر cron (الغلاف الجاهز lynis-scan.sh في /usr/local/bin/، راجع الملخص): 0 3 * * * /usr/local/bin/lynis-scan.sh >> /path/to/monitor/logs/cron.log 2>&1
بعد أول تشغيل، ستعرض صفحة «تدقيق Lynis» فورًا مؤشر التحصين والتحذيرات والتوصيات.
زر «تشغيل التدقيق» في صفحة Lynis. يشغّل lynis-scan.sh في الخلفية مباشرةً من اللوحة (دون انتظار cron): يعرض «جارٍ الفحص…» وعند الانتهاء يحدّث التقرير تلقائيًا. لذلك يحتاج مستخدم الويب إلى سطر sudoers لتشغيل السكربت — يضيفه المثبّت تلقائيًا في /etc/sudoers.d/monitor. إذا ثُبّتت اللوحة يدويًا/سابقًا، أضِف السطر بنفس المستخدم المذكور في الملف:
u=$(sudo awk '/NOPASSWD/ && !/lynis-scan/ {print $1; exit}' /etc/sudoers.d/monitor) [ -n "$u" ] && echo "$u ALL=(ALL) NOPASSWD: /usr/local/bin/lynis-scan.sh" | sudo tee -a /etc/sudoers.d/monitor sudo visudo -c && sudo chmod 440 /etc/sudoers.d/monitor

28. إعداد تقارير Logwatch

يجب أن يحفظ Logwatch التقارير اليومية في مجلد data/logwatch/ الخاص بالمشروع بصيغة .txt. يعرض المونيتور آخر تقرير والأرشيف.

# يوميًا (6:00) — سطر cron (الغلاف الجاهز logwatch_daily.sh في /usr/local/bin/، انظر الملخص): 0 6 * * * /usr/local/bin/logwatch_daily.sh >> /path/to/monitor/logs/cron.log 2>&1

وحدات اللوحة

29. مراقب الشبكة (مدمج)

لا يتطلب مراقب الشبكة أي تثبيت — فهو صفحة مدمجة في اللوحة. تعرض حالة الشبكة للسيرفر من مصادر محلية:

  • الواجهات وحركة البيانات — من /proc/net/dev؛
  • حالة الروابط (UP/DOWN) وعنوان IP — عبر ip؛
  • الاتصالات والمنافذ المستمعة — عبر ss؛
  • أحداث شبكة النواة خلال 24 ساعة — عبر journalctl -k.

تعمل المصادر الثلاثة الأولى دون sudo، لذا تظهر الواجهات وحركة البيانات والاتصالات والمنافذ فوراً. أما كتلة «أحداث النواة» فتستخدم journalctl -k — وتُقرأ عبر مجموعة systemd-journal («إعداد sudo»، البند 2)، ولا حاجة إلى sudo. للتحقق من أن كل شيء متاح لمستخدم الويب:

# التحقق باسم www-data (يعمل PHP تحته): sudo -u www-data bash -c 'cat /proc/net/dev' sudo -u www-data bash -c 'ip -o link show' sudo -u www-data bash -c 'ss -s' sudo -u www-data journalctl -k --no-pager -n 5
تعرض كتلة «أحداث شبكة النواة» أحداث حزمة الشبكة في النواة (تغيّر حالة الرابط up/down، أخطاء الحامل، «network unreachable»). لا تظهر هنا سجلات جدار الحماية UFW BLOCK — فهي في صفحتَي «جدار الحماية UFW» و«خريطة الهجمات». الكتلة الفارغة مع علامة خضراء = لم تحدث أعطال شبكة خلال اليوم.

30. القرص وSMART

تعرض الصفحة المدمجة ثلاثة أشياء:

  • أنظمة الملفات — امتلاء الأقسام (df)؛ يحمرّ الشريط عند ≥90%؛
  • وحدات التخزين — قائمة الأقراص (lsblk)، الحقيقية فقط (loop/snap مخفية)؛
  • الصحة (SMART) — حالة القرص وسماته (smartctl).

تعمل المساحة وقائمة الأجهزة فورًا دون إعداد. أما SMART فيتطلب حزمة smartmontools. لا يملك عملية الويب وصولًا مباشرًا إلى أجهزة الأقراص، لذلك تُلتقط بيانات SMART عبر cron إلى الملف data/disk/smart.txt، وتقرأه لوحة التحكم.

المهمة تُضاف إلى كرون الجذر (sudo crontab -e). يوضع الغلاف الجاهز smart-scan.sh في /usr/local/bin/ (chmod +x؛ راجع ملخص مهام cron) ويكتب بنفسه في data/disk/ الخاص باللوحة.

sudo apt install smartmontools # سطر cron (كل 30 دقيقة): */30 * * * * /usr/local/bin/smart-scan.sh >> /path/to/monitor/logs/cron.log 2>&1

يجد الغلاف smart-scan.sh بنفسه مجلد data/ الخاص باللوحة — لا حاجة لكتابة المسار. وفي الداخل يستبعد lsblk -e7,11 أقراص loop/cdrom.

على الأقراص الافتراضية (QEMU/KVM وما شابهها) عادةً ما تتوفر الحالة العامة فقط «الصحة: OK»، بينما قد تكون درجة الحرارة وساعات التشغيل والقطاعات المُعاد تخصيصها فارغة — وهذا طبيعي. أما على السيرفر الفعلي فتظهر جميع السمات.

31. الأداء (CPU/RAM/الشبكة/القرص)

تعرض الصفحة سِجل حِمل السيرفر خلال آخر 24 ساعة — Load Average، انشغال CPU وانتظار I/O، وRAM/Swap، وحركة الشبكة (استقبال/إرسال)، وI/O القرص (قراءة/كتابة)، وامتلاء القرص وinodes، وواصفات الملفات المفتوحة واتصالات MySQL، إضافةً إلى العدد الحالي لاتصالات TCP والعمليات. والنافذة الافتراضية 24 ساعة: تنقلها الأزرار في الأعلى إلى 7 أيام أو 30 يومًا.

يجمع البيانات cron/collect_metrics.php — كل 5 دقائق يكتب لقطة «خام» واحدة للعدّادات (/proc/loadavg، /proc/meminfo، /proc/stat، /proc/net/dev، /proc/diskstats، df/df -i، /proc/sys/fs/file-nr، SHOW GLOBAL STATUS LIKE 'Threads_connected') في جدول قاعدة البيانات system_metrics؛ أما النِسب والسرعات فتحسبها الصفحة بنفسها من الفرق بين اللقطتين المتجاورتين (امتلاء القرص/inodes/الواصفات/اتصالات MySQL قيمٌ لحظية، بلا إعادة حساب). لا حاجة إلى Sudo — تُقرأ المصادر دون صلاحيات root.

عمقان للتخزين. تبقى اللقطات «الخام» التي تُؤخذ كل خمس دقائق يومًا واحدًا (زائد ساعة احتياطية، حتى يبقى لأقدم نقطة في الرسم البياني سلفٌ تُحسب منه). ثم تُطوى كل ساعة منتهية في سطر واحد؛ وتُحفَظ هذه السلسلة الساعية 30 يومًا، وهي بالضبط ما تقرأه العروض «7 أيام» و«30 يومًا». وهكذا يكلّف شهر كامل من السجل نحو 720 سطرًا بدل نحو 8600.

في فترتَي 7 و30 يومًا تُعرَض متوسطات ساعية لا قياسات مفردة — إذ تُمهَّد القفزة القصيرة التي تستغرق خمس دقائق عند هذا المقياس، والصفحة تنبّه إلى ذلك. أما Load Average فيحفظ السطر الساعي متوسطه وذروته معًا، ولهذا يُظهر الرسم خطين. وبعد التحديث مباشرة تكون الفترات الطويلة فارغة («لا يوجد سجل لهذه الفترة بعد») — إذ تبدأ السلسلة الساعية بالتراكم من تلك اللحظة.
# سطر Cron (كل 5 دقائق): */5 * * * * /usr/local/bin/collect-metrics-all.sh >> /path/to/monitor/logs/cron.log 2>&1

الغلاف collect-metrics-all.sh (انظر ملخص مهام cron) يعثر بنفسه على جميع نُسخ اللوحة المثبَّتة على السيرفر ويشغّل cron/collect_metrics.php لكلٍّ منها باسم مالك الموقع.

إلى أن يعمل المُجمِّع مرتين على الأقل (أول ~10 دقائق بعد التثبيت)، تعرض الصفحة «جارٍ جمع البيانات» — تحتاج الرسوم البيانية إلى زوج واحد على الأقل من النقاط المتجاورة لحساب السرعات والنِسب.

أثقل العمليات. تحت الرسوم البيانية جدولان يعرض كل منهما خمس عمليات هي الأكثر استهلاكًا للمعالج:

  • «العمليات في آخر قياس» — ما الذي كان يُحمِّل الخادم لحظة أخذ آخر لقطة (الوقت مكتوب في ترويسة البطاقة)؛
  • «العمليات عند ذروة اليوم» — العمليات الخمس نفسها، لكن مأخوذة من القياس الذي بلغ فيه Load Average أعلى قيمة خلال الـ24 ساعة الأخيرة. وهي الجواب عن سؤال «ما الذي جرى ليلًا» بعدما تكون القفزة في الرسم قد مضت.

ويصف الجدولان دائمًا آخر 24 ساعة حتى لو كانت الرسوم تعرض شهرًا كاملًا: فلقطة العمليات لا توجد إلا في أسطر الخمس دقائق، وهذه لا تُحفَظ أكثر من يوم.

تُستبعَد من القائمة عمليات القياس نفسه (ps وسكربت PHP الذي يجمع البيانات وسلسلة cron/sudo فوقه) — وإلا لتصدّرت كل لقطة: إذ يُظهر ps لحظة انطلاقه استهلاكًا يقارب 100 % من المعالج. أما مهام cron الأخرى التي تعمل في الدقيقة نفسها فتظهر بالفعل، ولأجلها وُجد الجدول.

تنبيهات الحِمل (قسم «الإعدادات» ← «تنبيهات الحِمل») — عند تجاوز عتبة المعالج أو الذاكرة أو القرص أو inodes ترسل اللوحة إشعارًا عبر كل القنوات المفعّلة (Telegram والبريد الإلكتروني وwebhook والتنبيهات الفورية — القنوات نفسها التي يذهب بها التقرير اليومي؛ ولا حاجة إلى تفعيل شيء إضافي للتنبيهات)، ثم إشعارًا آخر عندما يعود المؤشر إلى وضعه الطبيعي. وما دامت العتبة متجاوَزة فلن يتكرر الإزعاج: لا يصل الإشعار التالي إلا بعد دورة «عاد إلى الطبيعي ← تجاوز العتبة من جديد».

تُفحص العتبات بواسطة collect_metrics.php نفسه عند كل تشغيل (كل 5 دقائق) — لا حاجة إلى cron منفصل. تُحفظ حالة «تم التنبيه / لم يتم بعد» في data/alerts_state.json، والعتبات في إعدادات اللوحة.

32. أحداث الأمان (مستشعر كل 5 دقائق)

يجيب التقرير اليومي عن سؤال «كيف حال الخادم». أما المستشعر فيجيب عن سؤال آخر — «ماذا حدث للتو». فكل 5 دقائق يسأل المصادر السريعة ولا يسجّل إلا ما تغيّر منذ الفحص السابق؛ وصفحة «أحداث الأمان» في القائمة تعرض ما عُثر عليه.

ولا يمسّ المستشعر الفحوص البطيئة — Lynis وdebsums وتحديثات الحزم ومدة شهادة SSL: فأرقامها تتغير مرة واحدة يوميًا على أي حال، وتبقى من شأن التقرير اليومي.

ما الذي يلاحظه — تسعة مصادر:

  • Fail2ban — عمليات حظر جديدة (تُقارَن قائمة العناوين المحظورة، لذا لا يُعدّ رفع الحظر حدثًا، ويُبلَّغ عن الحظر الساري مرة واحدة تمامًا)؛
  • CrowdSec — قرارات جديدة؛
  • Falco — أحداث من مستويات Emergency وAlert وCritical؛
  • Suricata — تنبيهات جديدة؛ وعلامة [Priority: 1] ترفع الأمر إلى مستوى حرج؛
  • ClamAV — أسطر FOUND جديدة في سجل الفحص؛
  • AIDE — تغيّرات في الملفات بحسب آخر فحص (أي ليس أكثر مما يعمل به هو نفسه وفق جدوله)؛
  • SSH — دخول ناجح بحساب root (حرج)، ودخول من عنوان لم يُرَ من قبل (تحذير)؛
  • خدمات الحماية — UFW وFail2ban وCrowdSec وSuricata وFalco: رسالة عند توقف الخدمة، وأخرى عند عودتها إلى العمل؛
  • المنافذ — منفذ صار متاحًا من الخارج؛ فإن كانت خلفه قاعدة بيانات أو ذاكرة تخزين مؤقت فالأمر حرج.

أما الأداة غير المثبَّتة، أو التي لا تستطيع اللوحة قراءة سجلها، فتبقى صامتة ببساطة — وهذا ليس خطأً ولا حدثًا.

الفحص الأول لا يرسل شيئًا. فكل مصدر يحتفظ بعلامة «إلى أين وصلت القراءة» (الملف data/secwatch_state.json)، والتشغيل الأول يكتب هذه العلامة فحسب. وإلا لجاءك عند تفعيل المراقبة إشعار بكل ما تراكم في السجلات على مدى أشهر.

الضبط — «الإعدادات» ← «مراقبة الأحداث»:

  • تفعيل المراقبة — ما دامت مغلقة فإن مهمة cron تعمل بلا طائل ولا تمتلئ القائمة؛
  • التنبيه ابتداءً من — «تحذير» أو «حرج». وما دون العتبة يدخل القائمة على أي حال، لكنه لا يدخل الإشعارات؛
  • الفاصل، دقيقة — أقل مدة بين إشعارين، والقيمة الافتراضية 15؛
  • ساعات الهدوء — نافذة بالصيغة 23-7 لا تُرسَل خلالها التحذيرات.
الأمور الحرجة تُرسَل فورًا — فلا الفاصل الزمني ولا ساعات الهدوء تحجزها: ومن أجلها وُجد مستشعر كل 5 دقائق. ومع ذلك هناك صمام أمان: ستة إشعارات في الساعة كحد أقصى — تحسّبًا لمصدر يبدأ «بالوميض».

وتذهب الإشعارات عبر القنوات نفسها التي يذهب بها التقرير اليومي (Telegram والبريد الإلكتروني وwebhook والتنبيهات الفورية) — دون حاجة إلى تفعيل شيء إضافي. وتُكتَب كل النتائج في القائمة بصرف النظر عن إرسال الإشعار من عدمه، وتُحفَظ 90 يومًا.

قائمة الأحداث. المرشِّحات: الفترة (24 ساعة أو 7 أو 30 أو 90 يومًا)، والأهمية، والمصدر؛ وتُعرَض آخر 500 سجل. وزر «افحص الآن» يشغّل الفحص نفسه الذي يشغّله cron — وهو مفيد بعد الضبط مباشرة كي لا تنتظر خمس دقائق؛ كما يذكر السبب حين لا يُرسَل أي إشعار («دون عتبة الأهمية»، «ساعات الهدوء»، «لم تُضبَط أي قناة إشعارات»). والعدّاد الأحمر بجانب عنصر القائمة هو عدد الأحداث الحرجة خلال الـ24 ساعة الأخيرة.

بطاقة العنوان. النقر على سطر في قائمة الأحداث أو في كتلة عناوين مترابطة يفتح كل ما هو معروف عن عنوان واحد: التسلسل الزمني لأحداثه، الدولة، وفي السطر الأول الخلاصة. سطر القائمة يفتح البطاقة عندما يخص الحدث عنوانًا واحدًا بالضبط؛ وإن كانت العناوين عدة، فالروابط هي العناوين داخل السطر. والخلاصات أربع:

  • الوصول محتمل — جرى تسجيل دخول ناجح من العنوان ورصدته دفاعات أخرى أيضًا، أو عمل AIDE أو ClamAV أو انفتح منفذ جديد بعد الدخول مباشرة. الحالة الوحيدة التي تستحق التحقق فورًا؛
  • تسجيل دخول من هذا العنوان — هناك تسجيل دخول ولا شيء غيره. عادةً هو المالك من مكان جديد، ولذلك لا تُصبغ البطاقة بالأحمر؛
  • محظور — رُصد العنوان وحُظر: عملت الحماية ولا حاجة إلى شيء؛
  • يحتاج إلى مراجعة — هناك اكتشافات لكن بلا حظر. إذا عاد العنوان مرارًا فاحظره يدويًا.

تحت التسلسل الزمني كتلة ما جرى على الخادم في الوقت نفسه: أحداث بلا عنوان أصلًا. لا يعرف AIDE من غيّر الملف، ولا يعرف ClamAV من جلب الملف المصاب. تُعرض تلك التي وقعت أثناء نشاط العنوان وخلال ست ساعات بعده. واقتران الدخول بما تلاه هو ما يفرّق بين محاولة ووصول فعلي.

الربط يقوم على العنوان. المهاجم الذي يغيّر عنوانه يقطع هذا الربط. تعرض البطاقة ما رأته وسائل الحماية، ولا تتعهد بالتمييز بين اختراق ودخولك أنت من مكان جديد.

الجدولة. تُضاف المهمة إلى crontab الخاص بـ root (sudo crontab -e) بإزاحة دقيقتين عن جمع القياسات، حتى لا تنطلق المهمتان معًا:

# كل 5 دقائق — فحص أحداث الأمان 2-57/5 * * * * /usr/local/bin/security-watch-all.sh >> /path/to/monitor/logs/cron.log 2>&1
شغّل الفحص عبر الغلاف وحده، ولا تستدعِ php cron/security_watch.php مباشرة أبدًا. فالغلاف يعثر على كل نسخ اللوحة المثبَّتة على الخادم ويشغّل الفحص باسم مالك الموقع — بصلاحيات sudo نفسها التي تستعملها اللوحة من الويب. أما الاستدعاء المباشر من crontab الخاص بـ root فسينشئ ملف الحالة data/secwatch_state.json مملوكًا لـ root، فيتوقف زر «افحص الآن» في اللوحة عن العمل.
وإذا كان الخادم قد أُعدّ بالتثبيت التلقائي فالمهمة مضافة سلفًا — ولا يبقى إلا تفعيل المراقبة في الإعدادات.

33. خادم الويب: الطلبات ورموز الاستجابة

تحلّل صفحة «خادم الويب» سجل الوصول وتبيّن كم كان عدد الطلبات، وأي نسبة منها انتهت بخطأ، ومن أرسلها. فـ ModSecurity يجيب عن سؤال «ما الذي حُجب»، وهذه الصفحة تجيب عن سؤال «ما الذي وصل إلى الموقع أصلًا».

ما الذي يظهر: عدد الطلبات، وRPS، ونسبة الأخطاء، وعدّاد مستقل للرمز 5xx، وحجم ما أُرسِل؛ ورسم بياني للطلبات بحسب الساعات؛ وتوزيع الرموز 2xx/3xx/4xx/5xx؛ والعناوين المتكررة، وعناوين IP المتكررة، والأخطاء المتكررة (الرمز مع المسار)، والعملاء (User-Agent). والفترة: 24 ساعة أو 7 أيام.

المصدر هو سجل الوصول بصيغة combined، ولذلك يصلح Nginx وApache معًا، ولا حاجة إلى أي وحدة إضافية. وتبحث اللوحة عن السجل بين الملفات القياسية:

  • /var/log/nginx/access.log
  • /var/log/apache2/access.log
  • /var/log/apache2/other_vhosts_access.log
  • /var/log/httpd/access_log

وإلى جانبها تفحص اللوحة الملفات المسماة *access*.log و*requests*.log في /var/log/nginx/ و/var/log/apache2/ و/var/log/httpd/. وبذلك يُعثر أيضًا على السجل الذي يكتبه موقع في ملف خاص به عبر التوجيه CustomLog — مثل arciveo-monitor_requests.log الذي ينشئه مثبّت Arcivéo.

يُقرأ سجل واحد فقط: فحين يكون Nginx أمام Apache سيؤدي جمع سجلين إلى عدّ كل طلب مرتين. وتأخذ اللوحة أول سجل من القائمة أعلاه كُتب فيه خلال اليوم الأخير (وتُجرَّب الملفات التي عُثر عليها بنمط الاسم بعده، من الأحدث إلى الأقدم)؛ وإن لم يُكتب في أي منها منذ يوم، فتأخذ أحدث سجل غير فارغ. لذلك لا يحجب السجلُ الذي أفرغه logrotate أو الذي تخلّف عن خادم ويب متوقف السجلَّ العامل. ويُقرأ آخر جزء من السجل (3 ميغابايت) ويُخزَّن الناتج مؤقتًا 5 دقائق — لذا قد لا تُغطّى الفترة المختارة بالكامل على موقع مزدحم؛ والتغطية الفعلية مكتوبة فوق الرسم البياني.

«لا تستطيع اللوحة قراءة سجل خادم الويب». السبب في الغالب هو الصلاحيات: فالسجلات ومجلدها تابعة لمجموعة adm، ومستخدم الويب ليس فيها. ويضيفه مثبّت Arcivéo إلى هذه المجموعة؛ أما بعد التثبيت اليدوي فيحلّ المشكلةَ غلافٌ صغير من root مسموح له بأمر واحد فقط — عرض السجل (وصفحة ModSecurity تعمل بالطريقة نفسها). ويختار الغلاف السجل وفق القواعد نفسها التي تتبعها اللوحة. والأمر يظهر في الصفحة ذاتها، وهو أيضًا هنا. الصقه كاملًا — فهو أمر واحد:
sudo tee /usr/local/bin/monitor-weblog >/dev/null <<'EOF' && sudo chmod 755 /usr/local/bin/monitor-weblog && echo 'www-data ALL=(root) NOPASSWD: /usr/local/bin/monitor-weblog' | sudo tee /etc/sudoers.d/monitor-weblog >/dev/null && sudo visudo -c #!/bin/sh L="/var/log/nginx/access.log /var/log/apache2/access.log /var/log/apache2/other_vhosts_access.log /var/log/httpd/access_log $(ls -t /var/log/nginx/*access*.log /var/log/apache2/*access*.log /var/log/apache2/*requests*.log /var/log/httpd/*access_log 2>/dev/null)" for f in $L; do [ -r "$f" ] && [ -n "$(find "$f" -size +0 -mmin -1440 2>/dev/null)" ] && exec tail -c 3000000 "$f"; done for f in $(ls -t $L 2>/dev/null); do [ -r "$f" ] && [ -s "$f" ] && exec tail -c 3000000 "$f"; done EOF

قد يختلف مستخدم الويب عن www-data — تحقّق بأي مستخدم يعمل تجمّع PHP-FPM الخاص بالموقع (ps -o user= -C php-fpm) وضعه في سطر sudoers. وإذا لم يتضمن اسم السجل access ولا requests، فأضف مساره في بداية السطر L=… داخل الغلاف.

«لا توجد سجلات للفترة المختارة» — أي أن السجل قُرئ لكن لم توجد فيه أسطر مطابقة: فإما أن الموقع لم يُفتَح فعلًا، وإما أن السجل دُوِّر للتو (logrotate) وبدأ من جديد.

محاولات استغلال ثغرات معروفة. تطابق اللوحة طلبات السجل مع تواقيع نحو عشرين استغلالًا شائعًا: PHP-CGI، واجتياز المجلدات في Apache، وPHPUnit، وLog4Shell، وثغرات الموجّهات والكاميرات وبوابات VPN. ولكل محاولة تبيّن هل يمكن أن تنجح على هذا الخادم، معتمدة على وقائع: إصدارات Apache وPHP المثبّتة، ووجود Java، ورمز استجابة الخادم لطلب الملف. لا يُعلَّم بالأحمر إلا ما يمكن أن ينجح فعلًا.

تقوية خادم الويب. تطلب اللوحة كل موقع على الخادم عبر 127.0.0.1 وتتحقق مما يتلقاه الزائر: هل يظهر إصدار خادم الويب وPHP، وهل طريقة TRACE مفعّلة، وهل توجد ترويسات الحماية Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy وContent-Security-Policy. تؤخذ المواقع من العنوان الذي تُفتح به اللوحة ومن ملفات المضيفين الافتراضيين إن استطاعت اللوحة قراءتها. تُحدَّث النتيجة كل 10 دقائق.

إذا نقص شيء يظهر أمر واحد أسفل الجدول. ينشئ ملفًا منفصلًا هو zz-arciveo-hardening.conf ولا يعيد تحميل خادم الويب إلا بعد نجاح اختبار الإعدادات؛ ولا تتكرر الترويسات التي يرسلها الموقع بنفسه. لا يُقترح CSP في سطر واحد: تُبنى السياسة لكل موقع على حدة، وإلا توقف الموقع عن تحميل سكربتاته وأنماطه وخطوطه. للتراجع عن التغيير في Apache:

sudo a2disconf zz-arciveo-hardening && sudo systemctl reload apache2
لا يُعلَّم التوقيع في صفحات الأخطاء (ServerSignature) إذا كان إصدار خادم الويب مخفيًا أصلًا: فبدون الإصدار لا يعرض إلا اسم الخادم واسم المضيف.

34. خريطة الهجمات (GeoIP)

تحدّد صفحة «خريطة الهجمات» الدولة من عنوان IP باستخدام الأمر geoiplookup. بدون حزمة GeoIP لن تُحدّد الدول ولن تظهر النقاط على الخريطة:

sudo apt install geoip-bin geoip-database # التحقق: geoiplookup 8.8.8.8
لا حاجة إلى Sudo — يمكن للجميع قراءة قاعدة البيانات /usr/share/GeoIP/GeoIP.dat، وتُخزَّن النتائج مؤقتًا في tmp/geoip_cache.json. أمّا الخريطة نفسها (Leaflet + بلاطات OpenStreetMap) فتُحمَّل في المتصفح — لذا يلزم اتصال بالإنترنت على الجهاز الذي فُتحت فيه اللوحة.

35. التعرض الخارجي والتحديثات والتحديثات التلقائية

بطاقتان مدمجتان في لوحة التحكم تعرضان لا حالة «تشغيل/إيقاف» الأداة، بل مستوى الحماية الفعلي للسيرفر. لا تتطلبان أي إعداد، وتُقرآن محليًا دون sudo.

التعرض الخارجي — عدد الخدمات التي تستمع على كل الواجهات (0.0.0.0/[::]) والمتاحة من الخارج. يُبرز باللون الأحمر إذا كانت قواعد البيانات أو التخزين المؤقت مكشوفة للخارج (MySQL، PostgreSQL، Redis، MongoDB، Memcached، Elasticsearch) — فهذه ثغرة مباشرة (−10 من تقييم الأمان). المصدر: ss -tuln.

إذا كانت البطاقة حمراء — أغلق قاعدة البيانات أمام العالم الخارجي: اربطها بـ 127.0.0.1 (bind-address في إعداد MySQL/PostgreSQL، وbind 127.0.0.1 في Redis) أو أغلق المنفذ في UFW.
«منفذ مفتوح» ≠ «متاح من الخارج». الخدمة التي تستمع على 127.0.0.1 (loopback) مرئية للسيرفر نفسه فقط — لا يمكن الوصول إليها من الخارج حتى لو كان المنفذ «مفتوحًا». لذلك فإن Postfix على المنفذ 25 المرتبط بـ loopback آمن: يضبط الإعداد التلقائي inet_interfaces = loopback-only (بالإضافة إلى smtpd_banner محايد — يعالج ملاحظة Lynis MAIL-8818 حول كشف الإصدار). بطاقة «التعرض الخارجي» تحتسب كمكشوف للخارج فقط ما يستمع على 0.0.0.0/[::]؛ أما خدمات loopback فلا تُحتسب.
Lynis MAIL-8818 يدويًا (إذا ثبّت البريد بنفسك): في /etc/postfix/main.cf اضبط smtpd_banner = $myhostname ESMTP (دون الإصدار ونظام التشغيل) وinet_interfaces = loopback-only، ثم sudo systemctl restart postfix.

تحديثات الأمان — عدد الرقع الأمنية التي تنتظر التثبيت وما إذا كانت هناك حاجة لإعادة التشغيل بعد تحديث النواة (−5 من تقييم الأمان عند وجود رقع). المصدر: /usr/lib/update-notifier/apt-check، والملف /var/run/reboot-required. القائمة التفصيلية — في صفحة «تحديثات الأمان».

# تثبيت التحديثات: sudo apt update && sudo apt upgrade # التحقق مما يستمع للخارج: ss -tuln | grep -E '0\.0\.0\.0|\[::\]'
تعمل بطاقة التحديثات على Ubuntu/Debian (update-notifier-common). إذا لم يكن apt-check موجودًا — يحتسب المونيتور الرقع عبر apt-get -s upgrade.

التحديثات الأمنية التلقائية (unattended-upgrades) — في صفحة «تحديثات الأمان» تعرض بطاقة منفصلة ما إذا كان التثبيت التلقائي للرقع الأمنية مفعّلًا ومتى جرى تشغيله آخر مرة. لا حاجة إلى sudo — تُقرأ الحالة عبر apt-config dump.

sudo apt install unattended-upgrades sudo dpkg-reconfigure -plow unattended-upgrades # تفعيل # التحقق مما هو مفعّل: apt-config dump | grep Unattended-Upgrade

الصيانة

36. النسخ الاحتياطي

النسخ الاحتياطي هو التأمين الأساسي: فقدان البيانات أخطر من أي اختراق. تحتاج شيئين — نسخة احتياطية للسيرفر/المواقع ونسخة منفصلة لقاعدة بيانات اللوحة (فيها المستخدمون ومفاتيح WebAuthn والإعدادات والترخيص).

الخيار A — HestiaCP: تبويب Backup لدى المستخدم ← زر إنشاء نسخة احتياطية (أو حسب جدول في إعدادات السيرفر). تشمل النسخة المواقع وقواعد بياناتها.

الخيار B — يدويًا (cron): تفريغ قاعدة البيانات + أرشفة مجلد data/ الخاص باللوحة:

# مهمة cron لـ root (sudo crontab -e) — نسخة احتياطية يومية في 2:30 (ضع أسماءك/مساراتك): 30 2 * * * mysqldump -u root MY_DB | gzip > /var/backups/monitor-db-$(date +\%F).sql.gz 40 2 * * * tar czf /var/backups/monitor-data-$(date +\%F).tar.gz -C /path/to/monitor data # حذف الأرشيفات الأقدم من 14 يومًا: 0 3 * * * find /var/backups -name 'monitor-*' -mtime +14 -delete
النسخة الاحتياطية على نفس السيرفر تحميك من الأخطاء، لكن ليس من فقدان السيرفر. انسخ الأرشيفات إلى تخزين خارجي (سيرفر آخر، S3، rclone إلى السحابة). تحقق من أن الاستعادة تعمل فعليًا.

37. تحديث ونقل اللوحة

الترقية إلى إصدار جديد. أنشئ نسخة احتياطية أولاً. ثم أعد رفع ملفات الكود مع الحفاظ على بياناتك:

  • استبدل (الكود): public/ وincludes/ وassets/ وcron/ وdatabase/، إضافةً إلى .htaccess الجذري (وحدة التحكم الأمامية — لا يجوز إبقاء التوجيه من الإصدار القديم) وmanifest.json وsw.js؛
  • لا تلمس: config.php (بيانات قاعدة البيانات) وdata/ (التقارير) وlogs/ وtmp/ (الجلسات والذاكرة المؤقتة).
# بعد الرفع — امسح ذاكرة PHP المؤقتة (إن كان opcache مفعّلاً): sudo systemctl reload php*-fpm
يعرض FileZilla الخطأ SSH_FX_PERMISSION_DENIED — Permission denied. ملفات اللوحة مملوكة لـwww-data (هكذا ضُبطت عند التثبيت)، بينما يتصل عميل SFTP بحسابك أنت الذي لا يملك صلاحية الكتابة. منح www-data ملكية اللوحة كاملةً «كي تعمل» هو تحديدًا ما يؤدي إلى هذا الخطأ؛ في الأسفل ثلاث طرق، كلٌّ منها يحل المشكلة.
# الخيار A (موصى به) — افصل المالكين: الكود لك، والمجلدات العاملة لسيرفر الويب. # سيرفر الويب لا يحصل على صلاحية الكتابة في كود اللوحة إطلاقًا: sudo chown -R deploy:www-data /path/to/monitor sudo chown -R www-data:www-data /path/to/monitor/data /path/to/monitor/tmp /path/to/monitor/logs sudo find /path/to/monitor -type d -exec chmod 755 {} \; sudo find /path/to/monitor -type f -exec chmod 644 {} \; sudo chmod 750 /path/to/monitor/data /path/to/monitor/tmp /path/to/monitor/logs sudo chmod 640 /path/to/monitor/config.php # الخيار B — قائمة ACL فوق المالكين الحاليين (دون نقل أي شيء): sudo apt install -y acl sudo setfacl -R -m u:deploy:rwX /path/to/monitor sudo setfacl -R -d -m u:deploy:rwX /path/to/monitor # الخيار C — عبر مجموعة www-data. أبسط، لكن صلاحية الكتابة على ملفات # اللوحة يحصل عليها سيرفر الويب أيضًا (مع ثغرة في PHP يمكن استبدال الكود): sudo usermod -aG www-data deploy sudo find /path/to/monitor -type d -exec chmod 2775 {} \; sudo find /path/to/monitor -type f -exec chmod 664 {} \; sudo chmod 640 /path/to/monitor/config.php sudo chmod 2750 /path/to/monitor/data /path/to/monitor/tmp /path/to/monitor/logs
لماذا الخيار A آمن. اللوحة تكتب في ثلاثة مجلدات فقط — data/ (التقارير) وtmp/ (الجلسات والذاكرة المؤقتة) وlogs/؛ وتبقى مملوكة لـwww-data. أما البقية فهي كود، ولا يحتاجه سيرفر الويب إلا للقراءة التي توفّرها مجموعة www-data بصلاحيات 644. ميزة جانبية: مع ثغرة في PHP لم يعد بالإمكان استبدال ملفات اللوحة. على لوحات الاستضافة (HestiaCP وما شابهها) لا حاجة للخيار A: فملفات الموقع مملوكة أصلاً للحساب الذي تدخل به عبر SFTP، وسيرفر الويب يقرؤها عبر المجموعة.
مأزق الخيار B: أي chmod لاحق على الملفات يعيد ضبط قناع ACL، فيختفي الوصول بصمت. إذا اصطدم الرفع من جديد بـPermission denied بعد «ترتيب الصلاحيات» — كرّر أمرَي setfacl كليهما.
البِت 2 في الخيار C هو setgid: الملفات المرفوعة عبر SFTP تبقى في مجموعة www-data، وإلا لن تستطيع اللوحة استبدالها. بعد الخيار C أعد الاتصال في FileZilla — المجموعة الجديدة لا تسري إلا عند تسجيل دخول جديد. التحقق: id deploy (يجب أن تظهر مجموعة www-data) وls -ld /path/to/monitor (drwxrwsr-x — حرف s يعني أن setgid مفعَّل).

النقل إلى سيرفر آخر:

  1. على السيرفر الجديد جهّز الموقع + HTTPS (راجع صفحة التثبيت اليدوي).
  2. انسخ كل ملفات اللوحة مع config.php وdata/.
  3. انقل قاعدة البيانات: mysqldump على القديم ← استيراد على الجديد؛ وصحّح بيانات قاعدة البيانات في config.php.
  4. كرّر على السيرفر الجديد: sudoers، والعضوية في المجموعة adm، ومهام cron.
  5. الترخيص مرتبط بالدومين — إذا كان الدومين نفسه، سيستمر المفتاح في العمل.

38. موقع ثانٍ على هذا السيرفر (نطاق إضافي)

اللوحة تعمل بالفعل، وعلى السيرفر نفسه تحتاج إلى موقع آخر — بنطاق خاص به إلى جانب المراقب. بعد الإعداد التلقائي يكون السيرفر Apache + PHP-FPM عادياً، لذا يحتاج الموقع إلى ثلاثة أشياء: مجلد خاص به، و vhost خاص به، وشهادة خاصة به. أما اللوحة فلا نلمسها: فهي تراقب السيرفر بأكمله، ولا حاجة إلى نسخة ثانية من أجل النطاق الثاني.

هذا القسم مخصص لسيرفر بدون لوحة استضافة. إذا كانت HestiaCP أو لوحة مشابهة مثبتة، فأضف النطاق من داخلها لا يدوياً. وإذا كنت تخطط لاستضافة مواقع كثيرة (مع البريد أيضاً)، فثبّت اللوحة قبل الإعداد التلقائي: يكتشفها السكربت وينتقل إلى الوضع الإضافي، بينما اللوحة المثبَّتة لاحقاً تعيد بناء إعدادات Apache والجدار الناري والبريد.
ما الذي تستبدله في الأوامر. site2.example.com هو عنوان الموقع الجديد. يمكن أن يكون نطاقاً منفصلاً (mycompany.com) أو نطاقاً فرعياً (shop.mycompany.com) — لا فرق بالنسبة إلى Apache، ويختلف فقط سجل DNS (الخطوة 1) وإصدار الشهادة (الخطوة 5). أما site2 فهو مجرد اسم مختصر للموقع: به سُمّي المجلد /var/www/site2 وملف الإعدادات site2.conf. ولا علاقة له بالنطاق، إذ يأخذ Apache العنوان من ServerName فقط؛ والاسم يمكن أن يكون أي شيء — مثلاً مع shop.mycompany.com من المريح اختيار shop: المجلد /var/www/shop، والإعدادات shop.conf.

1. DNS. في لوحة DNS لدى مُسجِّل النطاق أنشئ سجل A يشير إلى عنوان IP لهذا السيرفر:

# نطاق فرعي (shop.mycompany.com): النوع: A الاسم: shop القيمة: 203.0.113.10 TTL: 3600 # نطاق منفصل (mycompany.com) — سجلان، ليعمل أيضاً العنوان مع www: النوع: A الاسم: @ القيمة: 203.0.113.10 TTL: 3600 النوع: A الاسم: www القيمة: 203.0.113.10 TTL: 3600

بعد بضع دقائق تحقق: يجب أن يُعيد dig +short site2.example.com عنوان IP للسيرفر.

2. مجلد الموقع.

sudo mkdir -p /var/www/site2 sudo chown -R www-data:www-data /var/www/site2

3. الـ vhost. يُلصق المقطع في الطرفية كاملاً — ويُحدَّد مسار مقبس PHP-FPM تلقائياً:

PHPSOCK=$(ls -1 /run/php/php*-fpm.sock 2>/dev/null | head -1) # الكشف التلقائي عن مقبس PHP-FPM sudo tee /etc/apache2/sites-available/site2.conf > /dev/null <<'EOF' <VirtualHost *:80> ServerName site2.example.com # نطاق منفصل: احذف # من السطر أدناه ليُفتح الموقع مع www أيضاً. # أما النطاق الفرعي فلا يحتاج إلى هذا السطر. #ServerAlias www.site2.example.com DocumentRoot /var/www/site2 <Directory /var/www/site2> Options -Indexes +FollowSymLinks AllowOverride All Require all granted </Directory> <FilesMatch \.php$> SetHandler "proxy:unix:__PHPSOCK__|fcgi://localhost" </FilesMatch> ErrorLog ${APACHE_LOG_DIR}/site2_error.log CustomLog ${APACHE_LOG_DIR}/site2_access.log combined </VirtualHost> EOF sudo sed -i "s#__PHPSOCK__#${PHPSOCK}#" /etc/apache2/sites-available/site2.conf

4. فعِّل الموقع وتحقق من الإعدادات قبل إعادة التحميل:

sudo a2ensite site2.conf sudo apache2ctl configtest # المتوقع: Syntax OK sudo systemctl reload apache2

5. SSL. certbot مثبَّت مسبقاً بواسطة الإعداد التلقائي؛ وفي هذه المرحلة يجب أن يشير DNS إلى السيرفر:

# نطاق فرعي — عنوان واحد: sudo certbot --apache -d site2.example.com # نطاق منفصل — مع www مباشرة (يجب أن يشير سجلا A من الخطوة 1 إلى السيرفر، # وأن يكون www ضمن ServerAlias، وإلا فلن يستطيع certbot التحقق من العنوان الثاني): sudo certbot --apache -d site2.example.com -d www.site2.example.com

يُضاف النطاق الثالث وما بعده بالطريقة نفسها — كرِّر الخطوات 1–5 مع تغيير النطاق والمجلد.

مَن يستجيب للطلبات «الغريبة». إذا لم يطابق Host أي ServerName (دخول عبر عنوان IP أو نطاق غريب موجَّه إلى سيرفرك)، فإن Apache يقدّم أول موقع أبجدياً من المواقع المفعَّلة في /etc/apache2/sites-enabled/. والموقع الافتراضي 000-default يعطّله الإعداد التلقائي، لذا يبقى هذا الدور «المناوب» لـ vhost اللوحة (arciveo-monitor.conf) — وهذا لا يؤثر على المواقع التي تُفتح بأسمائها الخاصة. وإذا أردت أن يُفتح موقع آخر عبر عنوان IP، فسمِّ ملفه بحيث يسبق أبجدياً (مثلاً 000-site2.conf).
الحماية تشمل السيرفر كله: UFW و Fail2ban و CrowdSec و ModSecurity و Suricata تعمل بالفعل وتغطي الموقع الجديد تلقائياً، ولا حاجة إلى إعدادها على حدة. والمنفذان 80/443 مفتوحان أيضاً. وللموقع سجلاته الخاصة: site2_error.log و site2_access.log في /var/log/apache2/.
لا تضع مجلد الموقع الجديد داخل مجلد اللوحة — فجذر الويب للوحة محكوم بملف .htaccess خاص به (متحكم أمامي)، والموقع المتداخل سيقدّم شيئاً غير الذي تتوقعه. اجعل المواقع متجاورة: /var/www/monitor و /var/www/site2.

39. استعادة الوصول (فقدان المفتاح أو كلمة المرور أو حظر IP)

إذا تعذّر عليك تسجيل الدخول — يمكن إصلاح كل شيء مباشرةً في قاعدة البيانات من السيرفر. افتح قاعدة البيانات (الاسم من config.php):

sudo mysql MY_DB

فقدان مفتاح WebAuthn (تعذّر اجتياز العامل الثاني) — عطّل 2FA، وسجّل الدخول بكلمة المرور، ثم سجّل مفتاحًا جديدًا:

UPDATE users SET webauthn_enabled = 0;

نسيان كلمة المرور — عيّن تجزئة جديدة (أنشئها على السيرفر وضعها هنا):

# إنشاء تجزئة كلمة المرور الجديدة: php -r "echo password_hash('NEW_PASSWORD', PASSWORD_BCRYPT), \"\n\";" # في قاعدة البيانات (ضع التجزئة الناتجة): # UPDATE users SET password = '$2y$10$...' WHERE username = 'admin';

حظرت نفسك بمرشّح IP — عطّل القيد:

UPDATE settings SET value = '0' WHERE name = 'ip_restriction_enabled';
الوصول إلى قاعدة البيانات متاح دائمًا: sudo mysql على السيرفر، أو phpMyAdmin / قسم قاعدة البيانات في لوحة الاستضافة. بعد الاستعادة، أعد تفعيل WebAuthn ومرشّح IP.

40. جميع مهام cron في مكان واحد

ملخص المهام موجود في cron الخاص بـ root للسيرفر (تُضاف عبر sudo crontab -e). أبقِ فقط أسطر الأدوات التي تستخدمها؛ وعدّل المسارات لتناسب سيرفرك.

# cron المونيتور على السيرفر (root) — أضِفه عبر: sudo crontab -e # 01:30 — فحص ClamAV للمسارات الخطرة (web, home, temp) → بطاقتا «الملفات المفحوصة» و«آخر فحص» 30 1 * * * /usr/local/bin/clamav-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 02:00 — فحص سلامة الملفات بـ AIDE (يلزم --config صريح) 0 2 * * * /usr/bin/aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1 # عند الإقلاع — استعادة صلاحيات /var/lib/aide (ملف tmpfiles الحزمي # aide-common.conf يعيدها إلى 0700، فتفقد اللوحة رؤية القاعدة) @reboot chmod 755 /var/lib/aide # 03:00 — تدقيق أمني بـ Lynis 0 3 * * * /usr/local/bin/lynis-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 04:00 — تحديث قائمة الحظر ipsum (level 1) 0 4 * * * /usr/local/bin/load-ipsum.sh >> /path/to/monitor/logs/cron.log 2>&1 # مجموعة ipsum عند الإقلاع تُحمّلها خدمة ipsum-load.service (قبل الجدار الناري، وإلا # لن يرى UFW المجموعة في before.rules) — ليست cron. هنا فقط التحديث اليومي أعلاه. # 06:00 — تقرير Logwatch 0 6 * * * /usr/local/bin/logwatch_daily.sh >> /path/to/monitor/logs/cron.log 2>&1 # كل 30 دقيقة — فحص أقراص SMART */30 * * * * /usr/local/bin/smart-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 04:30 — سلامة الحزم بـ debsums 30 4 * * * /usr/local/bin/debsums-scan.sh >> /path/to/monitor/logs/cron.log 2>&1 # 08:00 — تقرير مجدول عبر البريد وTelegram 0 8 * * * /usr/local/bin/daily-report-all.sh >> /path/to/monitor/logs/cron.log 2>&1 # كل ساعة — تحديث قوائم الحزم (لبطاقة «تحديثات الأمان») 0 * * * * /usr/bin/apt-get update -qq >/dev/null 2>&1 # كل 5 دقائق — لقطة للموارد (CPU/RAM/الشبكة/القرص) لصفحة «الأداء» */5 * * * * /usr/local/bin/collect-metrics-all.sh >> /path/to/monitor/logs/cron.log 2>&1 # كل 5 دقائق، بإزاحة عن اللقطة أعلاه — مستشعر أحداث الأمان: # حظر جديد، تنبيهات IDS، خدمة حماية توقفت، منفذ انفتح. # وما دامت المراقبة غير مفعّلة في الإعدادات فلن تفعل هذه المهمة شيئًا. 2-57/5 * * * * /usr/local/bin/security-watch-all.sh >> /path/to/monitor/logs/cron.log 2>&1 # كل 15 دقيقة — ملخص الخادم إلى الحساب الشخصي، لتظهر عدة خوادم في قائمة واحدة. # وما دام الملخص غير مفعّل فلن تفعل هذه المهمة شيئًا. 3,18,33,48 * * * * /usr/local/bin/fleet-push-all.sh >> /path/to/monitor/logs/cron.log 2>&1
تفاصيل كل بند في الأقسام الخاصة به. تُضاف مهام النسخ الاحتياطي (القسم السابق) إلى هذا الـ cron نفسه. بعد التعديلات تحقّق: sudo crontab -l وأن خدمة cron فعّالة.
توقيت cron = المنطقة الزمنية للسيرفر، وليس TIMEZONE من config.php. الثابت TIMEZONE يؤثّر على PHP فقط (كيف تعرض اللوحة التواريخ)، لكن خادم cron يُشغّل المهام حسب توقيت نظام التشغيل. إن لم تتطابق منطقة السيرفر مع منطقتك، سيصلك تقرير «08:00» في وقت مختلف. مثال: السيرفر في منطقة أخرى (Europe/Berlin، UTC+2)، وأنت في الرياض (UTC+3) → سيصلك تقرير «08:00» في التاسعة صباحًا بتوقيتك. تحقّق ووحّد منطقة النظام مع منطقتك عند الحاجة:
# التحقق من المنطقة الزمنية الحالية للسيرفر: timedatectl # ضبط منطقتك (مثال) وإعادة تشغيل cron: sudo timedatectl set-timezone Asia/Riyadh sudo systemctl restart cron
بعد ذلك سيعمل السطر 0 8 * * * عند الساعة 08:00 بالتوقيت المحلي. وإلا لاضطررت إلى إزاحة cron نفسه، لكن مع التحول بين التوقيت الشتوي/الصيفي ستختلّ الإزاحة مجددًا — لذا الأصح ضبط منطقة النظام.
سكربتات تغليف جاهزة. توجد نسخها العاملة ونموذج crontab (crontab.txt) في مجلد system/ بجوار المشروع، خارج public_html. هذه ليست جزءًا من الموقع — لا حاجة لرفعها إلى جذر الويب؛ ضعها على السيرفر في المسارات النظامية (كما في crontab أعلاه):
  • lynis-scan.sh → /usr/local/bin/ (chmod +x) — يُشغّل lynis audit system، وأثناء الفحص يضع العلامة /tmp/lynis-running وينسخ lynis-report.dat إلى data/lynis/ في اللوحة؛
  • logwatch_daily.sh → /usr/local/bin/ (chmod +x) — يُنشئ تقرير Logwatch اليومي (sshd, fail2ban, sudo, postfix) في data/logwatch/؛
  • smart-scan.sh → /usr/local/bin/ (chmod +x) — يلتقط حالة الأقراص (smartctl) في data/disk/؛
  • debsums-scan.sh → /usr/local/bin/ (chmod +x) — يتحقق من سلامة الحزم (debsums) في data/debsums/؛
  • clamav-scan.sh → /usr/local/bin/ (chmod +x) — فحص ClamAV للمسارات الخطرة (web, home, temp)؛ يكتب الملخص في /var/log/clamav/scan.log حيث تقرأه صفحة ClamAV (سطر 01:30 في crontab أعلاه)؛
  • load-ipsum.sh → /usr/local/bin/ (chmod +x) — يحدّث مجموعة ipset باسم ipsum (level 1) في مكانها، دون كسر قواعد جدار الحماية الفعّالة (سطر 04:00 في crontab أعلاه)؛
  • daily-report-all.sh → /usr/local/bin/ (chmod +x) — يُشغّل تقرير cron/daily_report.php الخاص باللوحة (سطر 08:00 في crontab أعلاه)؛
  • daily_report.php — مضمّن أصلًا في اللوحة (cron/daily_report.php)، ويُشغّل عبر daily-report-all.sh، لا حاجة لوضعه منفصلًا؛
  • collect-metrics-all.sh → /usr/local/bin/ (chmod +x) — يُشغّل cron/collect_metrics.php الخاص باللوحة (صفحة «الأداء»، سطر */5 في crontab أعلاه)؛ collect_metrics.php مضمّن أصلًا في اللوحة، لا حاجة لوضعه منفصلًا؛
  • security-watch-all.sh ← /usr/local/bin/ (chmod +x) — يشغّل ملف اللوحة cron/security_watch.php باسم مالك الموقع (صفحة «أحداث الأمان»، السطر 2-57/5 في crontab أعلاه)؛ وsecurity_watch.php يأتي ضمن اللوحة أصلًا ولا يحتاج إلى تثبيت منفصل؛
  • fleet-push-all.sh ← /usr/local/bin/ (chmod +x) — يرسل ملخص الخادم إلى الحساب الشخصي عبر ملف اللوحة cron/fleet_push.php (السطر 3,18,33,48 أعلاه)؛
  • crontab.txt (system/cron/) — نموذج للمهام؛ أضِف الأسطر التي تحتاجها عبر sudo crontab -e.
يجب أن يتطابق مسار السكربت في crontab مع المكان الذي وضعته فيه.
كيفية وضع السكربت في /usr/local/bin/. لا يمكن الكتابة إليه مباشرةً من FileZilla — فالدليل ملك لـ root، وسيحصل عميل SFTP على SSH_FX_PERMISSION_DENIED. الترتيب كالتالي: أولًا ارفع الملف إلى /tmp (يكتب إليه الجميع)، ثم انقله إلى مكانه بأمر واحد:
# في FileZilla: في حقل «الموقع البعيد» أدخِل /tmp وارفع السكربت إليه، # ثم عبر SSH (install يضبط المالك والصلاحيات فورًا، لا حاجة لـ chown/chmod): sudo install -o root -g root -m 755 /tmp/lynis-scan.sh /usr/local/bin/lynis-scan.sh rm -f /tmp/lynis-scan.sh # التحقق: الملف في مكانه، الصلاحيات rwxr-xr-x، البنية سليمة bash -n /usr/local/bin/lynis-scan.sh && ls -l /usr/local/bin/lynis-scan.sh
لا تخلط بين الأدلة: المطلوب /tmp في جذر السيرفر — لا /var/tmp ولا tmp/ داخل اللوحة نفسها (الأخير ملك لـ www-data ومغلق أمام مستخدمك). في شجرة FileZilla يكون /tmp فرعًا في المستوى الأعلى، بجوار var، لا داخله.
هل ثبّت السيرفر بالإعداد التلقائي؟ هذه السكربتات ومهام cron الخاصة بها مثبّتة أصلًا بواسطة السكربت (في /usr/local/bin/، والسجل في /var/log/arciveo-cron.log) — لا حاجة لفعل أي شيء يدويًا.
أين تبحث السكربتات عن اللوحة. السكربتات محايدة تجاه النطاق: تجد تثبيتات اللوحة بتفحّص /home/*/web/*/public_html و/var/www/*، وتضع التقارير في data/ الخاص بها. إن كانت اللوحة في مسار آخر — أضِفه إلى سطر for app in … داخل السكربتات، وإلا فلن تصل تقارير Lynis/SMART/debsums/Logwatch إلى اللوحة.
cron.log وصلاحيات الوصول. ملف logs/cron.log يُنشئه أولًا cron الخاص بـ root — فيصبح ملكًا لـ root، ولن يتمكن تبويب «سجل cron» في اللوحة من قراءته أو تفريغه. أنشئ الملف مسبقًا باسم مستخدم الويب (مالك دليل الموقع؛ في HestiaCP هو الحساب، مثلًا admin) — عندئذٍ سيكتفي cron الخاص بـ root بالإلحاق دون تغيير المالك:
# الإنشاء مسبقًا باسم مستخدم الويب (قبل إضافة أسطر cron): sudo -u OWNER touch /path/to/monitor/logs/cron.log # إن كان cron.log قد أنشأه root — أعطِه لمستخدم الويب: sudo chown OWNER:OWNER /path/to/monitor/logs/cron.log sudo chmod 644 /path/to/monitor/logs/cron.log
لمعرفة مالك الدليل: stat -c %U /path/to/monitor.
الإدارة من اللوحة. في قسم «النظام» توجد صفحة «Crontab» — يمكن عرض المهام وإضافتها دون SSH. تحرّر اللوحة فقط المهام المُضافة عبرها هي (كتلة منفصلة في crontab الخاص بـ root، معلّمة بتعليقات خدمية)؛ أما كل ما هو موجود في crontab (القائمة أعلاه) فيظهر هناك للقراءة فقط ضمن قائمة «مهام السيرفر الأخرى» مع زر «نسخ إلى المحرّر» — وهو ينقل الجدول/الأمر فقط إلى نموذج الإضافة دون المساس بالسطر الأصلي. ولـ«نقل» مهمة قائمة إلى إدارة اللوحة — انسخها إلى المحرّر، احفظها، ثم احذف السطر القديم يدويًا (sudo crontab -e)، وإلا فستُنفّذ مرتين.
إعداد لمرة واحدة على السيرفر. تحتاج الصفحة إلى سكربت تغليف بصلاحيات مرتفعة — لا sudo crontab عاريًا (فسيكون ذلك تصعيدًا مباشرًا إلى root لأي شخص يحصل على وصول لجلسة اللوحة)، بل سكربت ضيّق بأمرين (list/set) يمسّ كتلته الخاصة فقط بين التعليقات الخدمية. ثبّته مرة واحدة:
sudo install -m 0755 -o root -g root /dev/stdin /usr/local/sbin/arciveo-cron <<'ARCIVEO_CRON_EOF' #!/bin/bash set -euo pipefail BEGIN='# >>> ARCIVEO-CRON-MANAGED (edited from the panel; do not edit by hand) >>>' END='# <<< ARCIVEO-CRON-MANAGED <<<' cmd=${1:-} case "$cmd" in list) [ "$#" -eq 1 ] || { echo "usage: ${0##*/} list" >&2; exit 2; } crontab -l -u root 2>/dev/null || true ;; set) [ "$#" -eq 1 ] || { echo "usage: ${0##*/} set (body on stdin)" >&2; exit 2; } body=$(cat) if grep -qF "$BEGIN" <<<"$body" || grep -qF "$END" <<<"$body"; then echo "invalid body: markers not allowed" >&2; exit 2 fi current=$(crontab -l -u root 2>/dev/null || true) tmp=$(mktemp); trap 'rm -f "$tmp"' EXIT { if grep -qF "$BEGIN" <<<"$current"; then awk -v b="$BEGIN" '{print} $0==b{exit}' <<<"$current" else [ -n "$current" ] && printf '%s\n' "$current" echo "$BEGIN" fi printf '%s\n' "$body" echo "$END" if grep -qF "$END" <<<"$current"; then awk -v e="$END" 'f{print} $0==e{f=1}' <<<"$current" fi } > "$tmp" crontab -u root "$tmp" ;; *) echo "usage: ${0##*/} <list|set>" >&2; exit 2 ;; esac ARCIVEO_CRON_EOF echo "www-data ALL=(ALL) NOPASSWD: /usr/local/sbin/arciveo-cron" | sudo tee -a /etc/sudoers.d/monitor sudo visudo -c
قد يختلف مستخدم الويب عن www-data — تحقّق من المستخدم الذي يعمل به مجمّع PHP-FPM للموقع (ps -o user= -C php-fpm)، وضعه في سطر sudoers.
رُفع الملف الجديد بمالك خاطئ — والصفحة تردّ «Access denied.». إن رُفع الملف public/crontab_monitor.php عبر FTP/SFTP باسم مستخدم نظام مختلف (مثلًا root) عن بقية ملفات الموقع، فلن يتمكن سيرفر الويب من قراءته. قارن المالك والصلاحيات مع ملف مجاور ووحّدهما:
ls -la public/crontab_monitor.php public/ssl_monitor.php sudo chown OWNER:OWNER public/crontab_monitor.php sudo chmod 644 public/crontab_monitor.php

التشخيص

41. الأداة مثبّتة لكن تظهر رسالة «غير مثبّتة»

يكتشف المونيتور وجود الأدوات عبر dpkg-query — قاعدة حزم APT. إذا ثُبّتت الأداة بطريقة أخرى غير apt (يدويًا، أو من snap، أو من المصدر)، فلن يراها dpkg.

# التحقق عبر dpkg: dpkg -l fail2ban | grep '^ii' dpkg -l auditd | grep '^ii' # إيجاد مسار الملف التنفيذي: which ufw fail2ban-client auditctl # اختبار sudo من www-data: sudo -u www-data sudo fail2ban-client status sudo -u www-data sudo ufw status verbose

42. معالجة المشكلات (500، لا توجد بيانات)

الخطأ 500 — تحقق من سجلات PHP وnginx والمونيتور نفسه:

tail -50 /var/log/nginx/error.log tail -50 /var/log/php*-fpm.log # سجلات المونيتور: tail -50 logs/monitor_$(date +%Y-%m-%d).log # صلاحيات المجلدات: ls -la data/ tmp/ logs/
اللوحة على لوحة استضافة (HestiaCP، ISPmanager، cPanel)؟ هناك لا يعمل PHP تحت www-data بل تحت حساب المستخدم (مثلاً admin — مالك دليل الموقع). كل قواعد sudo والعضوية في المجموعات (adm، systemd-journal) يجب إسنادها لهذا المستخدم، وإلا ستُظهر الوحدات «غير نشط / 0» رغم عمل الخدمات. لمعرفة مستخدم PHP الفعلي: ps -o user= -C php-fpm | sort -u أو مالك دليل الموقع stat -c '%U' /path/to/monitor. وبعدها استبدله بـ www-data في كل الأوامر أدناه. التثبيت التلقائي يحدد مستخدم الويب بنفسه ويسند له sudoers.

البيانات لا تظهر — في الغالب هي صلاحيات sudo غير مُعرّفة. تحقق من الأمر المحدد باسم مستخدم الويب (استبدل www-data بمستخدمك). العلم -n = بدون كلمة مرور، مثل PHP — إذا طُلبت كلمة مرور، فهذا يعني عدم وجود قاعدة في sudoers:

sudo -u www-data sudo -n fail2ban-client status sudo -u www-data sudo -n ufw status verbose sudo -u www-data sudo -n ipset list -t ipsum sudo -u www-data sudo -n /usr/sbin/ausearch -m USER_LOGIN -ts today sudo -u www-data sudo -n /usr/sbin/aa-status sudo -u www-data sudo -n /usr/sbin/psad --Status sudo -u www-data journalctl -u falco --no-pager -n 5
الوحدة تُظهر «غير نشط» / «0» رغم أن الأداة تعمل (مثلاً sudo aa-status في الطرفية يعرض الملفات الشخصية، بينما صفحة «AppArmor» تُظهر «غير نشط»). السبب: مستخدم الويب لا يملك صلاحية sudo على أمر هذه الوحدة. تحقق منه من القائمة أعلاه: إذا طُلبت كلمة مرور — أضف السطر الناقص إلى /etc/sudoers.d/monitor («إعداد sudo»). أوامر «جديدة» شائعة: /usr/sbin/aa-status (MAC)، /usr/sbin/psad --Status (PSAD).
إذا كانت صفحة معينة (Falco، ModSecurity، Auditd، منافذ UFW المفتوحة) فارغة — راجع القائمة في قسم sudo: على الأرجح لم يُسمح بـ apache2ctl أو ausearch أو aa-status أو ss، أو أن مستخدم الويب ليس في مجموعتَي adm/systemd-journal (منهما تُقرأ سجلات fail2ban/auth/modsec وjournalctl — Falco وأحداث النواة).

43. الصفحة فارغة رغم وجود البيانات على السيرفر

العرض: تتوفر بيانات على السيرفر (تظهر عبر shell)، لكن الصفحة تعرض «لا توجد بيانات» أو حالة غير صحيحة — مثلاً يكتب AIDE «غير مهيأة» رغم إنشاء القاعدة.

السبب هو open_basedir: تقيّد كثير من اللوحات وشركات الاستضافة تجمّع PHP-FPM بمجلد الدومين، لذا تُحظر دوال PHP مثل file_exists() وfile_get_contents() وfilemtime() على المسارات النظامية (/var/lib/aide، /var/log، /proc…). يتجاوز المونيتور ذلك بقراءة هذه المسارات عبر أوامر النظام القياسية (cat، test، stat).

# هل يظهر الملف عبر shell (بهذه الطريقة يقرأه المونيتور): sudo -u www-data bash -lc 'test -e /var/lib/aide/aide.db && echo VISIBLE || echo NO' # القيمة الحالية لـ open_basedir لتجمّع الدومين: grep -ri open_basedir /etc/php/*/fpm/pool.d/ 2>/dev/null
إذا كان shell «يرى» الملف (VISIBLE) لكن الصفحة لا تراه — فهذا open_basedir. الحل الصحيح هو القراءة عبر أوامر النظام (مطبَّق فعلاً لـ AIDE ومونيتور الشبكة). لا داعي لتوسيع open_basedir ليشمل /var و/proc، وهو أقل أماناً.

44. صفحة SSL لا تعمل

يتحقق المونيتور من الشهادات عبر الاتصال بالنطاقات مباشرةً على المنفذ 443. إذا كان النطاق غير متاح من السيرفر نفسه أو كان المنفذ محجوبًا بالجدار الناري، فلن ينجح التحقق.

# التحقق من الشهادة يدويًا: echo | openssl s_client -connect monitor.example.com:443 2>/dev/null \ | openssl x509 -noout -dates # التحقق من التوفر: curl -I https://monitor.example.com
يأخذ المونيتور النطاقات تلقائيًا من إعدادات nginx (/etc/nginx/sites-enabled/، /etc/nginx/conf.d/) وApache (/etc/apache2/sites-enabled/) بالإضافة إلى المضيف الحالي من HTTP_HOST.
الكشف التلقائي عن النطاقات الفرعية. يتم تحديد النطاقات الفرعية تلقائيًا من سجلات Certificate Transparency العامة والتحقق منها عبر الشبكة، حتى لو كانت مستضافة على سيرفرات أخرى. لا حاجة لإضافة أي شيء يدويًا.

45. ظهور قاعدة بيانات واحدة فقط من عدة قواعد

يتصل المونيتور بـ MySQL بمستخدم من config.php لا يملك سوى صلاحية الوصول إلى قاعدته. تُظهر MySQL في information_schema القواعد ذات الصلاحيات فقط — لذلك لا تظهر البقية.

لكي يرى المونيتور كل قواعد البيانات، امنح هذا المستخدم صلاحية القراءة فقط (مرة واحدة من root؛ ضع اسم المستخدم من config.php):

sudo mysql -u root GRANT SELECT, PROCESS, SHOW DATABASES ON *.* TO 'DB_USER'@'localhost'; FLUSH PRIVILEGES; EXIT;
SELECT ON *.* يمنح صلاحية القراءة فقط — لا يمكن تعديل أو حذف أو إنشاء أي شيء، وهو آمن للمراقبة.
بدون هذا الـ GRANT ترى اللوحة قاعدتها فقط — وهذا ليس خطأً بل تقييد للصلاحيات. لا تستخدم اللوحة أي sudo mysql: تُجلب قائمة القواعد عبر اتصال PDO الخاص بها.

46. لا يظهر PostgreSQL في صفحة «قاعدة البيانات»

يتطلب PostgreSQL صلاحية على مستوى المستخدم postgres، وهي غير متوفرة لمستخدم الويب في اللوحة. فتح sudo psql واسع من PHP غير آمن — بدلاً من ذلك تستدعي اللوحة غلافًا ضيقًا بلا معاملات يطبع فقط الإصدار وعدد الاتصالات وقائمة قواعد البيانات مع أحجامها. أنشئه:

sudo tee /usr/local/bin/monitor-pgstat >/dev/null <<'EOF' #!/bin/sh # Arciveo Security Monitor - read-only PostgreSQL version, connections and per-database size sudo -u postgres psql -tAc "SELECT version();" | grep -oE 'PostgreSQL [0-9.]+' echo "---" sudo -u postgres psql -tAc "SELECT count(*) FROM pg_stat_activity;" echo "---" sudo -u postgres psql -tAc "SELECT datname || '|' || pg_size_pretty(pg_database_size(datname)) FROM pg_database WHERE datistemplate = false;" EOF sudo chown root:root /usr/local/bin/monitor-pgstat sudo chmod 755 /usr/local/bin/monitor-pgstat # في /etc/sudoers.d/monitor (المستخدم = الذي يعمل تحته PHP-FPM): # www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-pgstat
إذا كنت لا تستخدم PostgreSQL — احذف سطر monitor-pgstat من sudoers (الخطوة 13 من التثبيت اليدوي) ولا تنشئ السكربت نفسه: ستبقى بطاقة PostgreSQL غير نشطة فقط.

47. عند إطلاق تنبيه — ماذا تفعل

تُظهر لوحة التحكم ما يحدث؛ وفيما يلي ما يجب فعله في الحالات النمطية. المبدأ العام: لا تُصب بالذعر، قارن الأمر بالنشاط المشروع (أفعالك، التحديثات، النسخ الاحتياطية)، وتعامل معه حسب خطورته.

  • خريطة الهجمات / كثرة عمليات الحظر في fail2ban — هذا أمر طبيعي لأي سيرفر على الإنترنت (البوتات تجرّب SSH/الويب باستمرار). المهم أن يعمل الحظر فعلياً. تأكد من أن الدخول عبر SSH يتم بالمفتاح فقط (كلمة المرور معطّلة)، وأن عنوان IP الخاص بك ضمن ignoreip.
  • حظر ModSecurity لبعض الطلبات — يصدّ WAF الهجمات على الموقع، وهذه وظيفته. إن جرى حظر حركتك المشروعة (إنذار خاطئ) — ابحث عن rule id في التفاصيل وأضِف استثناءً في إعدادات CRS.
  • AIDE: ملفات مُعدَّلة — قارن القائمة بما قمت به (تحديث الحزم، تعديل الإعدادات أمر طبيعي). أما تغيّر الملفات التنفيذية للنظام التي لم تلمسها فهو سبب للحذر. بعد التغييرات المشروعة، حدّث قاعدة بيانات AIDE.
  • debsums: ملفات تنفيذية/مكتبات مُعدَّلة (خارج /etc، خارج /usr/share) — احتمال تلاعب. تحقق من الحزمة: debsums PACKAGE_NAME، وعند الشك أعِد تثبيتها (apt install --reinstall).
  • ClamAV / maldet: عُثر على تهديد — افحص الملف في الحجر ولا تفتحه. إن كان قشرة ويب في مجلد الموقع — اعزل السيرفر وابحث عن نقطة الدخول (إضافة مصابة، تسريب بيانات وصول).
  • Falco: أحداث حرجة (تشغيل shell داخل حاوية، الوصول إلى ملفات حساسة) — حلّل الحدث: أي عملية، ومَن شغّلها. غالباً ما يكون نشاطاً إدارياً مشروعاً.
  • تعرّض خارجي: قاعدة بيانات/تخزين مؤقت بالأحمر — أغلقه فوراً: اربط الخدمة بـ127.0.0.1 أو أغلق المنفذ في UFW. هذه ثغرة حقيقية.
  • SSL على وشك الانتهاء / منتهٍ — جدّد الشهادة (يُجدَّد Let's Encrypt تلقائياً؛ وإن لم يفعل — تحقق من certbot renew أو الإعدادات في لوحة التحكم).
  • تحديثات أمنية في الانتظار — ثبّتها: sudo apt update && sudo apt upgrade؛ وبعد تحديث النواة أعِد تشغيل السيرفر.
علامات اختراق حقيقي (عمليات/مستخدمون مجهولون، ملفات تنفيذية مُعدَّلة، بريد مزعج صادر، مهام cron مجهولة): افصل السيرفر عن الوصول الخارجي، خذ نسخة احتياطية للتحليل، وإن كانت البيانات حرجة فأنشئ سيرفراً نظيفاً من نسخة احتياطية موثوقة — فتنظيف الروتكيت بشكل موثوق أمر صعب.