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 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 и т.д.) и перезапускает их при падении. Может слать алерты на 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
Монитор читает данные через 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/Сеть/Диск)

Страница показывает историю нагрузки сервера — 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-крон сервера (добавляются через sudo crontab -e). Оставьте только строки тех инструментов, что используете; поправьте пути под свой сервер.

# Серверный крон монитора (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) — не крон. В кроне только ежедневный рефреш выше. # 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
Подробности по каждому — в соответствующих разделах. Бэкап-задания (предыдущий раздел) добавляются в этот же крон. После правок проверьте: 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-крон — он будет принадлежать root, и вкладка «Журнал cron» в панели не сможет его ни прочитать, ни очистить. Создайте файл заранее от имени веб-пользователя (владелец каталога сайта; на HestiaCP это аккаунт, напр. admin) — тогда root-крон будет лишь дописывать, не меняя владельца:
# создать заранее от веб-пользователя (до добавления cron-строк): sudo -u OWNER touch /path/to/monitor/logs/cron.log # если cron.log уже создан root-кроном — отдать веб-пользователю: sudo chown OWNER:OWNER /path/to/monitor/logs/cron.log sudo chmod 644 /path/to/monitor/logs/cron.log
Узнать владельца каталога: stat -c %U /path/to/monitor.
Управление из панели. В разделе «Система» есть страница «Crontab» — можно смотреть и добавлять задания без SSH. Панель редактирует только задания, добавленные через неё же (отдельный блок в 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-задания): отключите сервер от внешнего доступа, снимите бэкап для анализа и, если данные критичны, поднимайте чистый сервер из доверенного бэкапа — вычистить руткит надёжно сложно.