FAQ

Це посібник зі встановлення, налаштування та обслуговування Arcivéo Security Monitor. Розділи згруповано: загальний огляд, розгортання панелі, підключення інструментів безпеки, вбудовані модулі та діагностика. Команди можна копіювати кнопкою праворуч.

З чого почати

01. Встановлення панелі — оберіть спосіб

Встановлення панелі — на окремих покрокових сторінках. Оберіть спосіб:

Не впевнені — обирайте автоматичне. Цей довідник лишається єдиним джерелом щодо SSL, інструментів, cron та діагностики — install-сторінки посилаються на його розділи, нічого не дублюючи.

Огляд

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
  • Очікують встановлення security-оновлення — −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, Email, webhook і push

Каналів чотири: Telegram, Email, webhook і push у браузер. Вони незалежні — вмикайте будь-які, хоч усі чотири. Цими самими каналами йдуть добовий звіт безпеки, сповіщення про навантаження та знахідки сенсора подій: налаштовуються вони один раз, тут, у розділі «Налаштування».

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. Два способи на вибір у «Налаштування» → 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 — розбирати текст повідомлення не потрібно.

Push-сповіщення. Повідомлення надходить просто в браузер, а якщо панель додано на головний екран телефона — як звичайне сповіщення застосунку; ані бота, ані поштового сервера при цьому не потрібно. «Налаштування» → Push-сповіщення: увімкніть перемикач і натисніть «Підключити цей пристрій» на кожному пристрої, який має отримувати сповіщення. Лічильник «Підключено пристроїв» показує, скільки їх.

Push працює лише через HTTPS (як і WebAuthn), а дозвіл потрібен двічі: спершу в браузері — запит з’явиться після кнопки «Підключити цей пристрій», — а потім у самій операційній системі. Якщо у Windows вимкнено загальний перемикач Параметри → Система → Сповіщення, браузер дозвіл отримає, панель відзвітує про надсилання, а сповіщення на екрані так і не з’явиться. Те саме дають режим «Не турбувати» та вимкнені сповіщення браузера в macOS (Системні параметри → Сповіщення).
Кнопка «Надіслати тест» є в кожного каналу й одразу його перевіряє. Розклад автоматичного звіту — через cron (розділ «Усі cron-завдання»): він викликає надсилання, а канали беруться з налаштувань.

Статус звіту: «УВАГА» або «ОК». Заголовок стає «УВАГА» лише за реальної проблеми чи дії, що очікує: знайдено загрозу ClamAV, зміни файлів в AIDE, критичні події Falco (Emergency/Alert/Critical за останні 24 год), впалий сервіс у Monit, потрібне перезавантаження, спливає SSL (≤14 днів) або чекають security-оновлення. Фоновий шум — SSH-перебори ботів, забанені fail2ban IP, алерти Suricata, попередження Lynis та вже відбиті запити ModSecurity — статус не піднімає, тож такі цифри у звіті самі по собі не означають «УВАГА».

07. Ліцензія — введення та активація

Детальні модулі моніторингу (Lynis, UFW, ModSecurity, карта атак, AIDE, ClamAV та ін.) відкриваються за наявності чинної ліцензії. Без неї дашборд, налаштування та акаунт працюють, а модулі показують картку «Потрібна ліцензія».

Після придбання в кабінеті у вас є код активації вигляду ARCIVEO-XXXX-XXXX-XXXX-XXXX. Його потрібно «активувати» на домен вашої панелі — це перетворить код на підписаний ліцензійний файл (блок [license]), який ви вставляєте в панель.

Як активувати (3 кроки):

  1. Візьміть код активації. Особистий кабінет my.arciveo.com → розділ «Ліцензії» / «Активація ліцензії» — скопіюйте код ARCIVEO-….
  2. Активуйте код на свій домен. Там же в кабінеті відкрийте «Активація ліцензії», введіть: код активації, ваш email і домен панелі (адреса, за якою відкривається монітор, напр. 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', 'Europe/Kyiv'); // ваш часовий пояс // --- Час сесії --- 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 = 1 година, 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, кількість jail’ів Fail2ban, бани за сьогодні, чи запущені CrowdSec, Suricata і Falco, загрози ClamAV, зміни AIDE, індекс Lynis, очікувані оновлення, чи потрібне перезавантаження, днів до завершення SSL, кількість небезпечних відкритих портів); останній замір навантаження (load, CPU, RAM, диск, inodes); лічильники подій за 24 години й остання критична подія. Ані журналів, ані паролів, ані вмісту файлів у зведенні немає.

Надсилає сервер, а не запитує кабінет. Тому у вашу мережу не потрібно відкривати вхід ззовні, і панель, закрита IP-фільтром, усе одно звітує. Вузол упізнається за доменом панелі, тож список не задвоюється після перезапуску чи зміни IP.
Сервер у кабінеті позначено як «мовчить» — отже, зведення давно не надходило. Перевірте по черзі: чи ввімкнено перемикач «Надсилати зведення», чи стоїть cron-рядок (sudo crontab -l), що відповідає кнопка «Надіслати зараз». Помилки надсилання пишуться в журнал застосунку з міткою FLEET — там буде видно, чи відхилено токен (HTTP 401), чи не пройшло саме з’єднання.

Інструменти безпеки

11. Брандмауер UFW

UFW (Uncomplicated Firewall) — простий інтерфейс до nftables/iptables. Закриває всі вхідні порти, крім явно дозволених. Сторінка «Брандмауер UFW» показує стан і правила.

sudo apt install ufw # Дозволити SSH (обов'язково ДО ввімкнення!) і веб sudo ufw allow OpenSSH sudo ufw allow 80,443/tcp # Закрити БД ззовні (доступ лише локально) sudo ufw deny 3306 # Увімкнути і перевірити sudo ufw enable sudo ufw status verbose
Перед ufw enable обов'язково дозвольте SSH (ufw allow OpenSSH), інакше втратите доступ до сервера.
«Зовнішня експозиція» на дашборді враховує UFW: порт, закритий правилом deny, не вважається доступним ззовні.
Skipping adding existing rule — це не помилка. UFW так повідомляє, що точно таке правило вже є, і повторно його не додає. Під час повторного запуску автоналаштування (воно ідемпотентне) це штатне повідомлення — реагувати не потрібно.

12. Встановлення Fail2ban

Автоматично блокує IP після перевищення кількості невдалих спроб входу. Аналізує логи SSH, nginx, Apache та інших сервісів.

sudo apt install fail2ban sudo systemctl enable --now fail2ban # Перевірити статус: sudo fail2ban-client status
Робоча конфігурація (jail.local з десятками jail'ів та автобаном з ipsum) — у наступному розділі.

13. Робоча конфігурація Fail2ban + ipsum

Базове встановлення — вище. Тут — робоча конфігурація, що дає десятки активних jail та тисячі блокувань: загальні налаштування, ключові jail і автобан шкідливих IP зі списку ipsum.

Файл /etc/fail2ban/jail.local — загальні налаштування та найважливіші jail:

[DEFAULT] bantime = 1w findtime = 900 maxretry = 3 backend = systemd banaction = nftables-multiport ignoreip = 127.0.0.1/8 ::1 <YOUR_IP> <TRUSTED_NETS> # Прогресивний бан: кожен повтор — довше bantime.increment = true bantime.factor = 2 bantime.maxtime = 5w bantime.rndtime = 300 [sshd] enabled = true maxretry = 5 bantime = -1 # перманентний бан за брутфорс SSH findtime = 3600 # Рецидивісти: хто отримав кілька банів — баниться назавжди [recidive] enabled = true logpath = /var/log/fail2ban.log banaction = %(banaction_allports)s bantime = -1 findtime = 86400 maxretry = 2 [http-get-dos] enabled = true maxretry = 100 findtime = 300 bantime = 1w # Веб-сервіси (apache-*, nginx-*, php-url-fopen, phpmyadmin-syslog): [nginx-http-auth] enabled = true port = http,https [apache-badbots] enabled = true port = http,https # … та решта jail за сервісами (dovecot, exim, postfix-sasl, # mysqld-auth, vsftpd, portscan, pam-generic) — enabled = true
У ignoreip обов’язково впишіть свій IP та довірені мережі, інакше можна забанити самого себе. Після правок: sudo fail2ban-client reload.

Автозавантаження блок-листа ipsum — до 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 у них уже немає). Надійніше додати власний крон з явним --config — він пише лог від root у режимі 644, і монітор читає його без додаткових груп:
# sudo crontab -e — щоденна перевірка о 02:00: 0 2 * * * /usr/bin/aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1 # Запустити зараз, не чекаючи розкладу: sudo bash -c 'aide --config /etc/aide/aide.conf --check > /var/log/aide/aide.log 2>&1'
Автовстановлення уже робить усе це: chmod 755 /var/lib/aide і крон перевірки о 02:00 — вручну нічого не потрібно.
Першу ініціалізацію робіть на чистому сервері — до встановлення вебзастосунків. Після легітимних змін перестворюйте базу: sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db.

17. Встановлення ClamAV

Антивірусний сканер для Linux. Особливо корисний для перевірки /var/www на PHP-шели та шкідливий код.

sudo apt install clamav clamav-daemon sudo systemctl enable --now clamav-daemon # Оновити базу сигнатур: sudo freshclam # Просканувати теку вручну: sudo clamscan -r /var/www --infected
Демон clamd показує «Неактивний» після enable --now? Три типові причини:

1. У конфізі залишився рядок Example — clamd відмовляється стартувати, доки він там є:

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

2. Не завантажено базу сигнатур — clamd не стартує без неї:

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

3. Просто завантажується — clamd вантажить ~8 млн сигнатур у пам'ять 30–60 с. Зачекайте й перевірте: systemctl is-active clamav-daemon (статус activating → ще вантажить).

Діагностика: sudo journalctl -u clamav-daemon -n 30 --no-pager.
На дашборді «Файлів перевірено: 0» / «Останнє сканування: —»? Демон clamd лише тримає сигнатури в пам'яті, сам він нічого не сканує за розкладом. Панель показує результати планового сканування, тому потрібен крон, який сканує та пише лог. Автовстановлення додає обгортку /usr/local/bin/clamav-scan.sh і крон о 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 працює на основі подій: він мовчить, поки все гаразд, і записує подію лише за аномалії (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 тощо) і перезапускає їх у разі падіння. Може надсилати сповіщення на email.

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
Monitor читає дані через 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-крон (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» одразу покаже hardening index, попередження та рекомендації.
Кнопка «Запустити аудит» на сторінці Lynis. Вона запускає lynis-scan.sh у фоні прямо з панелі (не чекаючи cron): показує «Сканування…» і після завершення сама оновлює звіт. Для цього вебкористувачу потрібен рядок sudoers на запуск скрипта — інсталятор додає його автоматично у /etc/sudoers.d/monitor. Якщо панель встановлювалася вручну/раніше, допишіть його тим самим користувачем, що вже вказаний у файлі:
u=$(sudo awk '/NOPASSWD/ && !/lynis-scan/ {print $1; exit}' /etc/sudoers.d/monitor) [ -n "$u" ] && echo "$u ALL=(ALL) NOPASSWD: /usr/local/bin/lynis-scan.sh" | sudo tee -a /etc/sudoers.d/monitor sudo visudo -c && sudo chmod 440 /etc/sudoers.d/monitor

28. Налаштування звітів Logwatch

Logwatch має зберігати щоденні звіти в папку data/logwatch/ проєкту у форматі .txt. Монітор показує останній звіт та архів.

# Щодня (6:00) — cron-рядок (готова обгортка logwatch_daily.sh у /usr/local/bin/, див. зведення): 0 6 * * * /usr/local/bin/logwatch_daily.sh >> /path/to/monitor/logs/cron.log 2>&1

Модулі панелі

29. Мережевий монітор (вбудований)

Мережевий монітор не потребує встановлення — це вбудована сторінка панелі. Вона показує мережевий стан сервера з локальних джерел:

  • інтерфейси та трафік — з /proc/net/dev;
  • стан лінків (UP/DOWN) та IP — через ip;
  • з'єднання та порти, що слухають, — через ss;
  • мережеві події ядра за 24 год — через journalctl -k.

Перші три джерела працюють без sudo, тому інтерфейси, трафік, з'єднання та порти видно одразу. Блок «Події ядра» використовує journalctl -k — він читається через групу systemd-journal («Налаштування sudo», п.2), sudo не потрібен. Перевірити, що все доступне вебкористувачу:

# Проверка от имени www-data (под ним работает PHP): sudo -u www-data bash -c 'cat /proc/net/dev' sudo -u www-data bash -c 'ip -o link show' sudo -u www-data bash -c 'ss -s' sudo -u www-data journalctl -k --no-pager -n 5
Блок «Мережеві події ядра» показує події мережевого стека ядра (зміна лінка up/down, помилки несучої, «network unreachable»). Записи брандмауера UFW BLOCK сюди не потрапляють — вони на сторінках «Брандмауер UFW» та «Карта атак». Порожній блок із зеленою галкою = за добу мережевих збоїв не було.

30. Диск і SMART

Вбудована сторінка показує три речі:

  • Файлові системи — заповнення розділів (df); шкала червоніє при ≥90%;
  • Накопичувачі — список дисків (lsblk), лише реальні (loop/snap приховані);
  • Здоров'я (SMART) — статус диска й атрибути (smartctl).

Місце та список пристроїв працюють одразу, без налаштування. Для SMART потрібен пакет smartmontools. Веб-процес не має прямого доступу до дискових пристроїв, тому SMART знімається за cron у файл data/disk/smart.txt, а панель його читає.

Завдання — у 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') у таблицю БД 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 хвилин після встановлення), сторінка показує «дані збираються» — графікам потрібна щонайменше одна пара сусідніх точок, щоб обчислити швидкості та відсотки.

Топ процесів. Під графіками — дві таблиці з п’яти найненажерливіших за CPU процесів:

  • «Процеси в останньому замірі» — що навантажувало сервер на момент останнього знімка (час указано в заголовку картки);
  • «Процеси в момент піку за добу» — ті самі п’ять, але зняті в замірі з найбільшим Load Average за останні 24 години. Це відповідь на питання «що це було вночі», коли сплеск на графіку вже минув.

Обидві таблиці завжди описують добу, навіть коли графіки показують місяць: знімок процесів є лише в п’ятихвилинних рядків, а вони довше за добу не зберігаються.

Власні процеси заміру (ps, PHP-скрипт збору й ланцюжок cron/sudo над ним) із переліку виключаються — інакше вони посідали б перші рядки в кожному знімку: ps у момент запуску показує майже 100 % CPU. Решта завдань cron, запущених у ту саму хвилину, до таблиці потрапляють — саме їх там і корисно побачити.

Сповіщення про навантаження (розділ «Налаштування» → «Сповіщення про навантаження») — при перевищенні порогу CPU/RAM/диска/inodes панель надсилає сповіщення всіма ввімкненими каналами (Telegram, Email, webhook, push — тими самими, що й добовий звіт; окремо вмикати їх для алертів не потрібно), і ще одне — коли метрика повернулася до норми. Поки поріг утримується, повторно не спамить: наступне сповіщення прийде лише після циклу «відновилося → знову перевищило».

Пороги перевіряє той самий 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-хвилинний сенсор і потрібен. Запобіжник усе ж є: не більше ніж 6 сповіщень на годину — на випадок джерела, що почало «блимати».

Сповіщення йдуть тими самими каналами, що й добовий звіт (Telegram, Email, webhook, push) — вмикати їх окремо не потрібно. Усі знахідки записуються у стрічку незалежно від того, пішло сповіщення чи ні, і зберігаються 90 днів.

Стрічка. Фільтри: період (24 години, 7, 30 або 90 днів), важливість і джерело; показуються останні 500 записів. Кнопка «Перевірити зараз» запускає рівно ту саму перевірку, що й cron, — зручно одразу після налаштування, щоб не чекати п’ять хвилин; вона ж покаже причину, якщо сповіщення не пішло («нижче порогу важливості», «тихі години», «не налаштовано жодного каналу»). Червоний лічильник біля пункту меню — кількість критичних подій за останні 24 години.

Картка адреси. Клік по рядку стрічки або по рядку блоку Пов’язані адреси відкриває все, що відомо про одну адресу: хронологію її подій, країну і — першим рядком — висновок. Рядок стрічки веде на картку, коли подія стосується рівно однієї адреси; якщо адрес кілька, клікабельні самі адреси всередині рядка. Висновків чотири:

  • Можливий доступ — з адреси був успішний вхід, і вона ж потрапляла під інші захисти, або одразу після входу спрацювали AIDE, ClamAV чи відкрився новий порт. Єдиний випадок, коли варто перевірити, ваш це вхід чи ні;
  • Вхід із цієї адреси — вхід є, інших спрацювань немає. Зазвичай це власник з нового місця, тому картка не фарбується в червоне;
  • Заблоковано — адресу спіймали й заблокували: захист відпрацював, робити нічого;
  • Потребує перевірки — спрацювання є, а блокування не було. Якщо адреса повертається, її варто закрити вручну.

Нижче хронології — блок Що відбувалося на сервері в той самий час: події, у яких адреси немає в принципі. AIDE не знає, хто змінив файл, ClamAV не знає, хто приніс заражений. Показано ті з них, що припали на час активності адреси та на шість годин після. Саме зв’язка входу з тим, що сталося слідом, і відрізняє спробу від справжнього доступу.

Зв’язок будується за адресою. Атакувальник, який змінює адресу, цей зв’язок розриває. Картка показує те, що бачили захисти, і не береться відрізнити зламування від вашого власного входу з нового місця.

Розклад. Завдання ставиться в root-крон (sudo crontab -e) зі зсувом на 2 хвилини від збору метрик, щоб дві задачі не стартували водночас:

# кожні 5 хвилин — перевірка подій безпеки 2-57/5 * * * * /usr/local/bin/security-watch-all.sh >> /path/to/monitor/logs/cron.log 2>&1
Запускайте лише через обгортку, а не php cron/security_watch.php напряму. Обгортка знаходить усі встановлення панелі на сервері й запускає перевірку від власника сайту — з тими самими правами sudo, якими панель користується з вебу. Прямий виклик із root-крона створить файл стану data/secwatch_state.json із власником root, і кнопка «Перевірити зараз» у панелі перестане працювати.
Ставили сервер автоналаштуванням — завдання вже додано, лишається ввімкнути спостереження в налаштуваннях.

33. Вебсервер: запити та коди відповідей

Сторінка «Вебсервер» розбирає журнал доступу й показує, скільки було запитів, яка частина завершилася помилкою і хто ці запити робив. ModSecurity відповідає на питання «що заблоковано», ця сторінка — на питання «що взагалі йшло на сайт».

Що видно: кількість запитів, RPS, частка помилок, окремий лічильник 5xx і обсяг відданого трафіку; графік запитів за годинами; розподіл кодів 2xx/3xx/4xx/5xx; часті адреси, часті IP, часті помилки (код плюс шлях) і клієнти (User-Agent). Період — 24 години або 7 днів.

Джерело — журнал доступу у форматі combined, тому підходять і Nginx, і Apache, і жодного додаткового модуля не потрібно. Панель шукає журнал серед стандартних файлів:

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

Крім них, панель перевіряє файли *access*.log і *requests*.log у каталогах /var/log/nginx/, /var/log/apache2/ і /var/log/httpd/. Так знаходиться і журнал, який сайт пише у власний файл директивою CustomLog, — наприклад, arciveo-monitor_requests.log, який створює інсталятор Arcivéo.

Читається лише один журнал: якщо Nginx стоїть перед Apache, додавання двох журналів порахувало б кожен запит двічі. Береться перший журнал зі списку вище, у який писали за останню добу (знайдені за маскою перевіряються після нього, від свіжіших до старіших); якщо за добу не писали в жоден — найсвіжіший непорожній. Тому журнал, що спорожнів після logrotate або залишився від вимкненого вебсервера, не затуляє робочий. Читається останній фрагмент журналу (3 МБ), результат кешується на 5 хвилин — тому на навантаженому сайті вибраний період може бути покритий не повністю; фактичне охоплення підписано над графіком.

«Журнал вебсервера недоступний панелі». Причина майже завжди у правах: журнали та їхній каталог належать групі adm, а вебкористувач до неї не входить. Інсталятор Arcivéo додає його до цієї групи; після ручного встановлення допоможе маленька обгортка від root, якій дозволено рівно одну дію — показати журнал (так само влаштована сторінка ModSecurity). Обгортка вибирає журнал за тими самими правилами, що й панель. Команда виводиться просто на сторінці; ось вона ж. Вставляйте її повністю — це одна команда:
sudo tee /usr/local/bin/monitor-weblog >/dev/null <<'EOF' && sudo chmod 755 /usr/local/bin/monitor-weblog && echo 'www-data ALL=(root) NOPASSWD: /usr/local/bin/monitor-weblog' | sudo tee /etc/sudoers.d/monitor-weblog >/dev/null && sudo visudo -c #!/bin/sh L="/var/log/nginx/access.log /var/log/apache2/access.log /var/log/apache2/other_vhosts_access.log /var/log/httpd/access_log $(ls -t /var/log/nginx/*access*.log /var/log/apache2/*access*.log /var/log/apache2/*requests*.log /var/log/httpd/*access_log 2>/dev/null)" for f in $L; do [ -r "$f" ] && [ -n "$(find "$f" -size +0 -mmin -1440 2>/dev/null)" ] && exec tail -c 3000000 "$f"; done for f in $(ls -t $L 2>/dev/null); do [ -r "$f" ] && [ -s "$f" ] && exec tail -c 3000000 "$f"; done EOF

Вебкористувач може відрізнятися від www-data — перевірте, під ким працює пул PHP-FPM сайту (ps -o user= -C php-fpm), і підставте його в рядок sudoers. Якщо в назві журналу немає ні access, ні requests, допишіть його шлях на початок рядка L=… усередині обгортки.

«За вибраний період записів немає» — журнал прочитано, але відповідних рядків у ньому не знайшлося: або сайт справді не відкривали, або журнал щойно провернувся (logrotate) і почався заново.

Спроби відомих вразливостей. Панель звіряє запити з журналу із сигнатурами двох десятків поширених експлойтів: PHP-CGI, обхід каталогів в Apache, PHPUnit, Log4Shell, вразливості роутерів, камер і VPN-шлюзів. Для кожної спроби вона відповідає, чи може та спрацювати на цьому сервері, і спирається на факти: встановлені версії Apache і PHP, наявність Java, код відповіді сервера на запит файлу. Червоним позначено лише те, що справді може спрацювати.

Захист вебсервера. Панель запитує кожен сайт сервера через 127.0.0.1 і дивиться, що отримує відвідувач: чи видно версію вебсервера і PHP, чи ввімкнено метод TRACE, чи є захисні заголовки Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy і Content-Security-Policy. Сайти беруться з адреси, за якою відкрито панель, і з файлів віртуальних хостів, якщо панель може їх прочитати. Результат оновлюється раз на 10 хвилин.

Якщо чогось бракує, під таблицею з’являється одна команда. Вона створює окремий файл zz-arciveo-hardening.conf і перезавантажує вебсервер тільки після перевірки конфігурації; заголовки, які сайт уже віддає сам, не дублюються. CSP одним рядком не пропонується: політику збирають під конкретний сайт, інакше він перестане завантажувати власні скрипти, стилі й шрифти. Скасувати зміни на Apache можна так:

sudo a2disconf zz-arciveo-hardening && sudo systemctl reload apache2
Підпис на сторінках помилок (ServerSignature) не позначається, якщо версію вебсервера вже приховано: без версії він показує лише назву сервера та ім’я хоста.

34. Карта атак (GeoIP)

Сторінка «Карта атак» визначає країну за IP командою geoiplookup. Без пакета GeoIP країни не визначатимуться і точки на карті не з’являться:

sudo apt install geoip-bin geoip-database # Перевірка: geoiplookup 8.8.8.8
Sudo не потрібне — база /usr/share/GeoIP/GeoIP.dat доступна для читання всім, результати кешуються в tmp/geoip_cache.json. Сама карта (Leaflet + плитки OpenStreetMap) завантажується в браузері — потрібен інтернет на комп’ютері, де відкрито панель.

35. Зовнішня експозиція, оновлення та автооновлення

Дві вбудовані картки дашборда, що показують не «увімк./вимк.» інструмента, а реальну захищеність сервера. Встановлення не потребують, читаються локально без sudo.

Зовнішня експозиція — скільки сервісів слухають усі інтерфейси (0.0.0.0/[::]) і доступні ззовні. Підсвічує червоним, якщо назовні стирчать СУБД чи кеш (MySQL, PostgreSQL, Redis, MongoDB, Memcached, Elasticsearch) — це пряма діра (−10 до Оцінки безпеки). Джерело: ss -tuln.

Якщо картка червона — закрийте СУБД для зовнішнього світу: прив’яжіть до 127.0.0.1 (bind-address у конфізі MySQL/PostgreSQL, bind 127.0.0.1 у Redis) або закрийте порт у UFW.
«Відкритий порт» ≠ «доступний ззовні». Сервіс, що слухає 127.0.0.1 (loopback), видно лише самому серверу — ззовні на нього не потрапити, навіть якщо порт «відкритий». Тому Postfix на порту 25, прив’язаний до loopback, безпечний: автоналаштування ставить inet_interfaces = loopback-only (плюс нейтральний smtpd_banner — закриває зауваження Lynis MAIL-8818 про розкриття версії). Картка «Зовнішня експозиція» рахує назовні лише те, що слухає 0.0.0.0/[::]; loopback-сервіси туди не потрапляють.
Lynis MAIL-8818 вручну (якщо ставили пошту самі): у /etc/postfix/main.cf задайте smtpd_banner = $myhostname ESMTP (без версії та ОС) і inet_interfaces = loopback-only, потім sudo systemctl restart postfix.

Оновлення безпеки — скільки security-патчів чекають установлення й чи потрібне перезавантаження після оновлення ядра (−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) — на сторінці «Оновлення безпеки» окрема картка показує, чи ввімкнено автоматичне встановлення security-патчів і коли воно запускалося востаннє. 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/ панелі:

# 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-завдання в одному місці

Зведення завдань — у root-cron сервера (додаються через 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 — звіт за розкладом на Email і Telegram 0 8 * * * /usr/local/bin/daily-report-all.sh >> /path/to/monitor/logs/cron.log 2>&1 # щогодини — оновлення списків пакетів (для картки «Оновлення безпеки») 0 * * * * /usr/bin/apt-get update -qq >/dev/null 2>&1 # кожні 5 хв — знімок ресурсів (CPU/RAM/мережа/диск) для сторінки «Продуктивність» */5 * * * * /usr/local/bin/collect-metrics-all.sh >> /path/to/monitor/logs/cron.log 2>&1 # кожні 5 хв, зі зсувом від знімка вище — сенсор подій безпеки: нові бани, # спрацювання IDS, зупинка захисту, відкриття порту. # Поки спостереження вимкнено в налаштуваннях, завдання нічого не робить. 2-57/5 * * * * /usr/local/bin/security-watch-all.sh >> /path/to/monitor/logs/cron.log 2>&1 # кожні 15 хв — зведення по серверу в особистий кабінет, щоб кілька серверів # були видні одним списком. Поки зведення вимкнено, завдання нічого не робить. 3,18,33,48 * * * * /usr/local/bin/fleet-push-all.sh >> /path/to/monitor/logs/cron.log 2>&1
Подробиці щодо кожного — у відповідних розділах. Завдання резервного копіювання (попередній розділ) додаються в цей самий cron. Після правок перевірте: sudo crontab -l і що cron-служба активна.
Час cron = часовий пояс сервера, а не TIMEZONE з config.php. Константа TIMEZONE впливає лише на PHP (як панель показує дати), але cron-демон запускає завдання за системним часом ОС. Якщо пояс сервера не збігається з вашим, звіт «08:00» надійде не в той час. Приклад: сервер стоїть в іншому поясі (Europe/Berlin, UTC+2), а ви — у Києві (UTC+3) → звіт «08:00» надійде о 09:00 за вашим часом. Перевірте й за потреби приведіть пояс системи до свого:
# Перевірити поточний пояс сервера: timedatectl # Встановити свій пояс (приклад) і перезапустити cron: sudo timedatectl set-timezone Europe/Kyiv 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 першим створює root-cron — він належатиме root, і вкладка «Журнал cron» у панелі не зможе його ні прочитати, ні очистити. Створіть файл заздалегідь від імені вебкористувача (власник каталогу сайту; в HestiaCP це акаунт, напр. admin) — тоді root-cron лише дописуватиме, не змінюючи власника:
# створити заздалегідь від вебкористувача (до додавання cron-рядків): sudo -u OWNER touch /path/to/monitor/logs/cron.log # якщо cron.log уже створено root-cron — віддати вебкористувачу: 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 (список вище), показано там read-only списком «Інші завдання сервера» з кнопкою «Скопіювати в редактор» — вона лише переносить розклад/команду у форму додавання, вихідний рядок не чіпає. Щоб «перевести» наявне завдання під керування панелі — скопіюйте його в редактор, збережіть, потім видаліть старий рядок вручну (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, якого веб-користувач панелі не має. Відкривати з PHP широкий sudo psql небезпечно — натомість панель викликає вузьку обгортку без параметрів, яка лише виводить версію, кількість з'єднань і список баз з розмірами. Створіть її:

sudo tee /usr/local/bin/monitor-pgstat >/dev/null <<'EOF' #!/bin/sh # Arciveo Security Monitor - read-only PostgreSQL version, connections and per-database size sudo -u postgres psql -tAc "SELECT version();" | grep -oE 'PostgreSQL [0-9.]+' echo "---" sudo -u postgres psql -tAc "SELECT count(*) FROM pg_stat_activity;" echo "---" sudo -u postgres psql -tAc "SELECT datname || '|' || pg_size_pretty(pg_database_size(datname)) FROM pg_database WHERE datistemplate = false;" EOF sudo chown root:root /usr/local/bin/monitor-pgstat sudo chmod 755 /usr/local/bin/monitor-pgstat # у /etc/sudoers.d/monitor (користувач = той, під яким працює PHP-FPM): # www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-pgstat
Якщо PostgreSQL не використовуєте — приберіть рядок monitor-pgstat із sudoers (крок 13 ручного встановлення) і сам скрипт не створюйте: картка PostgreSQL просто залишиться неактивною.

47. Спрацював алерт — що робити

Панель показує, що відбувається; нижче — що робити в типових ситуаціях. Загальний принцип: не панікувати, звірити з легітимною активністю (ваші дії, оновлення, резервні копії) і реагувати за серйозністю.

  • Карта атак / багато банів fail2ban — це норма для будь-якого сервера в інтернеті (боти постійно перебирають SSH/веб). Головне, щоб бани спрацьовували. Переконайтеся, що вхід через SSH — лише за ключем (пароль вимкнено), а ваша IP-адреса в ignoreip.
  • ModSecurity заблокував запити — WAF відбиває атаки на сайт, це його робота. Якщо блокується ваш легітимний трафік (хибне спрацювання) — знайдіть rule id у деталях і додайте виняток у конфіг CRS.
  • AIDE: змінено файли — звірте список із тим, що ви робили (оновлення пакетів, правка конфігів — норма). Зміни системних бінарників, яких ви не торкалися, — привід насторожитися. Після легітимних змін оновіть базу AIDE.
  • debsums: змінено бінарники/бібліотеки (поза /etc, поза /usr/share) — потенційно підміна. Звірте пакет: debsums PACKAGE_NAME, за сумніву перевстановіть його (apt install --reinstall).
  • ClamAV / maldet: виявлено загрозу — перевірте файл у карантині, не відкривайте його. Якщо це вебшел у каталозі сайту — ізолюйте сервер і шукайте точку входу (вразливий плагін, витік доступів).
  • Falco: критичні події (запуск shell у контейнері, доступ до чутливих файлів) — розберіть подію: чий процес, що запускав. Часто це легітимна адмін-активність.
  • Зовнішня експозиція: червоним СУБД/кеш — негайно закрийте: прив'яжіть сервіс до 127.0.0.1 або закрийте порт в UFW. Це справжня діра.
  • SSL спливає / сплив — продовжте сертифікат (Let's Encrypt продовжується сам; якщо ні — перевірте certbot renew або налаштування в панелі).
  • Оновлення безпеки очікують — установіть: sudo apt update && sudo apt upgrade; після оновлення ядра перезавантажте сервер.
Ознаки реального зламу (невідомі процеси/користувачі, змінені бінарники, вихідний спам, невідомі cron-завдання): відключіть сервер від зовнішнього доступу, зробіть резервну копію для аналізу і, якщо дані критичні, розгортайте чистий сервер із довіреної резервної копії — надійно вичистити руткіт складно.