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 hardening index < 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, ולחצו “שמור ושלח בדיקה”.

אימייל. שתי דרכים לבחירה ב“הגדרות” ← Email:

  • 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]), שאותו אתם מדביקים בפאנל.

איך מפעילים (3 שלבים):

  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/Jerusalem'); // אזור הזמן שלך // --- זמן הפעלה --- 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. API לקריאה בלבד (JSON ו-Prometheus)

הלוח סגור מאחורי כניסה עם סיסמה, ואם מסנן ה-IP מופעל — גם מאחוריו. לתוכנה לא מתאים אף אחד מהשניים, ולכן למערכות חיצוניות יש כניסה משלהן — שתי כתובות לקריאה בלבד המוגנות באסימון. האסימון אינו משנה דבר בשרת: אפשר רק לשלוף איתו נתונים.

הפעלה — “הגדרות” ← “API לקריאה בלבד”: המתג “הפעלת ה-API”; האסימון נוצר אוטומטית בשמירה הראשונה. הכפתור “אסימון חדש” מנפיק אסימון אחר ובאותו רגע מנתק את כל מי שהשתמש בקודם.

  • /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 — ה-API כבוי בהגדרות. בקשות שנדחו נכתבות ליומן האפליקציה יחד עם כתובת ה-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, מספר ה-jails של 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 # חסימה קבועה על ניסיון brute-force ב-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” מציג כמה נחסמו באופן מונע.

ההבדל פשוט: תגובתי — “אלה תקפו וקיבלו חסימה”, מונע — “אלה נחסמו עוד לפני הניסיון”. בעבר הוזרם ל-recidive באופן מלאכותי list-3 של ipsum (מכאן החלוקה הישנה “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 — התעבורה מכתובות ה-IP הללו נחסמת בפועל. הכלל ממוקם אחרי 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 הטרמינל תקוע 5–15 דקות על השורה Running aide --init... — זה תקין (חישוב האש של כל מערכת הקבצים, עומס על הדיסק). אל תפסיקו ב-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 כבר אינו קיים בהם). אמין יותר להוסיף cron משלכם עם --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 ו-cron בדיקה ב-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
ה-daemon‏ 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” / “סריקה אחרונה: —”? ה-daemon‏ 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. בקובץ /etc/monit/monitrc חייב להיות מופעל ממשק ה-HTTP (בלוק set httpd עם allow localhost), אחרת monit status יחזיר שגיאה.
בלוח הבקרה מופיע “0 שירותים במעקב”? שתי סיבות. (1) ממשק ה-HTTP כבוי — בקובץ monitrc השורה set httpd מסומנת כהערה (כברירת מחדל היא מופיעה כ-# 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 (דפדפנים, לקוחות torrent וכדומה). כשקיימים פרופילים כאלה, הכרטיס “פרופילים טעונים” הופך לענבר ומציג את מספרם — לדוגמה 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
כדאי להעביר ל-enforce פרופילים ש-Ubuntu השאירה בכוונה ב-unconfined רק באופן מודע: הם כבויים לא בטעות, אלא כי אחרת עבודת התוכניות עצמן נשברת. פרופילים ב-complain — עניין אחר: שם הכללים כבר כתובים ורק לא מיושמים.

26. התקנת debsums (שלמות חבילות)

debsums בודק שקבצי החבילות המותקנות תואמים לסכומי הביקורת מהמאגר — מזהה קבצי מערכת בינאריים מוחלפים (משלים את AIDE). בדיקה מלאה נמשכת 1–2 דקות, ולכן מופעלת דרך cron, והלוח קורא את התוצאה מ־data/debsums/debsums.log וממיין אותה לקטגוריות בעצמו (חשובים רק קבצים בינאריים וספריות).

המשימה נכנסת ל־root-cron (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. תהליך ה-Web אינו ניגש ישירות להתקני הדיסק, ולכן ה-SMART נאסף באמצעות cron אל הקובץ data/disk/smart.txt, והלוח קורא אותו.

המשימה נמצאת בקרון של root (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') לטבלת ה-DB 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), בהיסט של 2 דקות מאיסוף המדדים, כדי שהשתיים לא יתחילו יחד:

# כל 5 דקות — בדיקת אירועי אבטחה 2-57/5 * * * * /usr/local/bin/security-watch-all.sh >> /path/to/monitor/logs/cron.log 2>&1
הריצו את הבדיקה רק דרך ה-wrapper, לעולם לא ישירות עם php cron/security_watch.php. ה-wrapper מוצא את כל התקנות הלוח בשרת ומריץ את הבדיקה בשם בעל האתר — עם אותן הרשאות 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 מוסיף אותו לקבוצה זו; אחרי התקנה ידנית יעזור wrapper קטן של root שמותר לו דבר אחד בלבד — להציג את היומן (דף ModSecurity פועל באותו אופן). ה-wrapper בוחר את היומן לפי אותם כללים כמו הלוח. הפקודה מוצגת בדף עצמו; והנה היא גם כאן. הדביקו אותה במלואה — זו פקודה אחת:
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=… בתוך ה-wrapper.

“אין רשומות לטווח שנבחר” — היומן נקרא, אך לא נמצאו בו שורות מתאימות: או שהאתר באמת לא נפתח, או שהיומן זה עתה התחלף (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 במקום אחד

סיכום המשימות נמצא בcrontab של 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 — דוח מתוזמן לאימייל ולטלגרם 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” יגיע ב-09:00 לפי הזמן שלכם. בדקו ובמידת הצורך התאימו את אזור הזמן של המערכת לשלכם:
# בדיקת אזור הזמן הנוכחי של השרת: timedatectl # הגדרת אזור הזמן שלכם (דוגמה) והפעלה מחדש של cron: sudo timedatectl set-timezone Asia/Jerusalem 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 כבר נוצר על ידי cron של 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. הלוח עורך רק משימות שנוספו דרכו (בלוק נפרד ב-root-crontab, המסומן בהערות שירות); כל מה שכבר קיים ב-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: אותרה איום — בדוק את הקובץ בהסגר, אל תפתח אותו. אם זהו web-shell בתיקיית האתר — בודד את השרת וחפש את נקודת הכניסה (תוסף פגיע, דליפת הרשאות).
  • Falco: אירועים קריטיים (הרצת shell במכולה, גישה לקבצים רגישים) — נתח את האירוע: של מי התהליך, מה הריץ אותו. לעיתים קרובות זו פעילות ניהול לגיטימית.
  • חשיפה חיצונית: מסד נתונים/מטמון באדום — סגור מיד: קשר את השירות ל-127.0.0.1 או סגור את הפורט ב-UFW. זהו פרצה אמיתית.
  • SSL עומד לפוג / פג — חדש את התעודה (Let's Encrypt מתחדש לבד; אם לא — בדוק את certbot renew או את ההגדרות בדשבורד).
  • עדכוני אבטחה ממתינים — התקן: sudo apt update && sudo apt upgrade; אחרי עדכון הליבה אתחל את השרת.
סימנים לפריצה אמיתית (תהליכים/משתמשים לא מוכרים, בינאריות ששונו, ספאם יוצא, משימות cron לא מוכרות): נתק את השרת מגישה חיצונית, צור גיבוי לצורך ניתוח, ואם הנתונים קריטיים — הקם שרת נקי מגיבוי מהימן — קשה לנקות rootkit באופן אמין.