FAQ

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

من أين تبدأ

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

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

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

نظرة عامة

02. ما هو Arcivéo Monitor

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

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

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

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

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

لمراقبة عدة سيرفرات، ثبّت المونيتور على كل واحد منها على حدة، بدومين فريد.

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
  • توجد تحديثات أمان بانتظار التثبيت — −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 والبريد الإلكتروني

يمكن للوحة إرسال تقرير الأمان إلى Telegram وإلى البريد (بضغطة زر أو حسب الجدولة). يُضبط ذلك في قسم «الإعدادات».

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_...) ونطاق المرسل المؤكَّد.
زر «إرسال اختبار» يفحص القناة فورًا. جدولة التقرير التلقائي تتم عبر 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. جدار الحماية 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 أن قاعدة مطابقة تمامًا موجودة بالفعل ولا يضيفها مجددًا. عند إعادة تشغيل الإعداد التلقائي (وهو عملية عديمة التأثير التراكمي) تكون هذه رسالة اعتيادية — لا حاجة للتدخل.

10. تثبيت Fail2ban

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

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

11. إعداد عملي لـ 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 للمعاودين الحقيقيين فقط، والوقائي كله على جدار الحماية.

12. قائمة الحظر 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 — أعلاه). عند التثبيت التلقائي لا حاجة لفعل أي شيء يدويًا.

13. تثبيت 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.

14. تثبيت 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.

15. تثبيت 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.

16. تثبيت 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 — راجع قسم «الصفحة فارغة رغم وجود البيانات على السيرفر».

17. تثبيت 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
التثبيت التلقائي يقوم بذلك بنفسه — لا حاجة لفعله يدويًا.

18. تثبيت 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 (يمكن لسيرفر الويب قراءة السجل). لا حاجة لضبط ذلك يدوياً على تثبيت جديد.

19. تثبيت 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 وأدرجها في القائمة. أما إذا كان الغلاف قديماً (بلا هذا القسم) — فسيعرض القسم تحذير «غير متاح» فقط، وبقية الصفحة تعمل كالسابق.

20. تثبيت 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.

21. تثبيت 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

22. تثبيت 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 ستكون الصفحة فارغة — وهذا طبيعي ما لم تحدث عمليات فحص.

23. 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 فأمرها مختلف: قواعدها مكتوبة بالفعل ولكنها غير مطبَّقة فحسب.

24. تثبيت 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 وما شابه) — بطاقة «الملفات الثنائية / المكتبات» تعرض هذه تحديدًا.

25. إعداد تقارير 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

26. إعداد تقارير 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

وحدات اللوحة

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

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

  • الواجهات وحركة البيانات — من /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» و«خريطة الهجمات». الكتلة الفارغة مع علامة خضراء = لم تحدث أعطال شبكة خلال اليوم.

28. القرص و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»، بينما قد تكون درجة الحرارة وساعات التشغيل والقطاعات المُعاد تخصيصها فارغة — وهذا طبيعي. أما على السيرفر الفعلي فتظهر جميع السمات.

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

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

يجمع البيانات 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. تُحذف النقاط الأقدم من 24 ساعة تلقائيًا عند كل كتابة.

# سطر 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 دقائق بعد التثبيت)، تعرض الصفحة «جارٍ جمع البيانات» — تحتاج الرسوم البيانية إلى زوج واحد على الأقل من النقاط المتجاورة لحساب السرعات والنِسب.

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

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

30. خريطة الهجمات (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) فتُحمَّل في المتصفح — لذا يلزم اتصال بالإنترنت على الجهاز الذي فُتحت فيه اللوحة.

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

بطاقتان مدمجتان في لوحة التحكم تعرضان لا حالة «تشغيل/إيقاف» الأداة، بل مستوى الحماية الفعلي للسيرفر. لا تتطلبان أي إعداد، وتُقرآن محليًا دون 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

الصيانة

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

النسخ الاحتياطي هو التأمين الأساسي: فقدان البيانات أخطر من أي اختراق. تحتاج شيئين — نسخة احتياطية للسيرفر/المواقع ونسخة منفصلة لقاعدة بيانات اللوحة (فيها المستخدمون ومفاتيح 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 إلى السحابة). تحقق من أن الاستعادة تعمل فعليًا.

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

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

  • استبدل (الكود): 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_DENIEDPermission 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. الترخيص مرتبط بالدومين — إذا كان الدومين نفسه، سيستمر المفتاح في العمل.

34. استعادة الوصول (فقدان المفتاح أو كلمة المرور أو حظر 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.

35. جميع مهام 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
تفاصيل كل بند في الأقسام الخاصة به. تُضاف مهام النسخ الاحتياطي (القسم السابق) إلى هذا الـ 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 مضمّن أصلًا في اللوحة، لا حاجة لوضعه منفصلًا؛
  • 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

التشخيص

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

يكتشف المونيتور وجود الأدوات عبر 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

37. معالجة المشكلات (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 وأحداث النواة).

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

العرض: تتوفر بيانات على السيرفر (تظهر عبر 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، وهو أقل أماناً.

39. صفحة 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 العامة والتحقق منها عبر الشبكة، حتى لو كانت مستضافة على سيرفرات أخرى. لا حاجة لإضافة أي شيء يدويًا.

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

يتصل المونيتور بـ 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 الخاص بها.

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

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

sudo tee /usr/local/bin/monitor-pgstat >/dev/null <<'EOF' #!/bin/sh # Arciveo 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 غير نشطة فقط.

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

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

  • خريطة الهجمات / كثرة عمليات الحظر في 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 مجهولة): افصل السيرفر عن الوصول الخارجي، خذ نسخة احتياطية للتحليل، وإن كانت البيانات حرجة فأنشئ سيرفراً نظيفاً من نسخة احتياطية موثوقة — فتنظيف الروتكيت بشكل موثوق أمر صعب.
Arcivéo - Security Monitor © 2026