Есть два типа администраторов, которые приходят к теме настройки ClamAV. Первые - те, кто только что включил clamonacc на нагруженном сервере и обнаружил, что система начала задыхаться: CPU под 100%, приложения лагают, логи пухнут тысячами строк в час. Вторые - те, кто прочитал предыдущий опыт первых и теперь с опаской смотрит на on-access сканирование, считая его нежизнеспособным инструментом. Обе группы правы в своей реакции, но неправы в выводах. ClamAV с реальной защитой файловой системы работает - просто конфигурация по умолчанию для этого не предназначена.
Прежде чем лезть в конфиги, стоит понять, из каких частей состоит эта система и как они взаимодействуют. clamd - демон, который держит базы сигнатур в памяти и обрабатывает запросы на сканирование. clamonacc - отдельный процесс, который подписывается на события ядра через API fanotify и при каждом обращении к файлу отправляет его на проверку в clamd. freshclam - демон обновления сигнатурных баз. clamdscan - клиент для ручного запуска сканирования через сокет clamd. Все четыре части работают в связке, и проблемы с производительностью почти всегда возникают из-за неправильного взаимодействия между ними, а не из-за слабости самого движка.
Архитектурная ловушка, в которую падают все новички
Первая и самая болезненная ошибка - использование clamscan вместо clamd + clamdscan для регулярных проверок. clamscan загружает всю базу сигнатур заново при каждом запуске. По состоянию на начало 2024 года эта база требует минимум 1,6 ГБ оперативной памяти только для загрузки, а в пике обновления - вдвое больше. На сервере с 4 ГБ ОЗУ каждый запуск clamscan - это удар по всей системе.
clamd загружает базу один раз при старте и держит её в памяти постоянно. Все запросы на сканирование идут через Unix-сокет и обрабатываются уже прогретым движком. Разница в скорости обработки одного файла между clamscan и clamdscan достигает порядка величины.
Проверить, что именно используется сейчас, и посмотреть на реальное потребление памяти:
# Смотрим, что работает
ps aux | grep -E "clam|fresh"
# Проверяем потребление памяти clamd
ps -o pid,rss,vsz,comm -p $(pgrep clamd)
# Проверяем подключение к сокету
echo PING | socat - UNIX-CONNECT:/run/clamav/clamd.ctl
# → PONG (значит, clamd жив и отвечает)
Если clamd не запущен, а сканирование идёт через clamscan по расписанию - это первое, что нужно исправить ещё до настройки on-access сканирования.
Правильная конфигурация clamd.conf - баланс между защитой и нагрузкой
Конфигурация clamd сосредоточена в /etc/clamav/clamd.conf. Параметры по умолчанию ориентированы на минимальную конфигурацию, а не на продуктивную нагрузку. Вот что нужно пересмотреть в первую очередь.
MaxThreads определяет, сколько файлов clamd сканирует параллельно. Дефолтное значение - 10. Для сервера с 4+ ядрами и on-access сканированием это значение часто слишком низкое: при высокой файловой активности очередь начинает расти быстрее, чем clamd её разгребает, и fanotify начинает блокировать доступ к файлам в ожидании вердикта. MaxQueue должен быть минимум вдвое больше MaxThreads - это задокументированное требование официальной man-страницы:
# Формула безопасного значения MaxQueue (из официальной документации):
# MaxThreads * MaxRecursion + MaxQueue - MaxThreads + 6 < RLIMIT_NOFILE
# Проверяем текущий лимит файловых дескрипторов
ulimit -n # обычно 1024 по умолчанию
cat /proc/sys/fs/file-max # системный максимум
# Поднимаем лимит для clamav если нужно
echo "clamav soft nofile 16384" >> /etc/security/limits.conf
echo "clamav hard nofile 16384" >> /etc/security/limits.conf
Полный блок оптимизированных параметров для сервера среднего класса (8+ ядер, 16+ ГБ RAM):
# /etc/clamav/clamd.conf
# --- Сокет (предпочтительнее TCP для локального использования)
LocalSocket /run/clamav/clamd.ctl
FixStaleSocket yes
# --- Потоки и очередь
MaxThreads 16 # примерно 2 потока на ядро CPU
MaxQueue 64 # минимум MaxThreads * 2, но не больше лимита fd
IdleTimeout 60 # ждать новых задач 60 секунд перед засыпанием
# --- Лимиты сканирования
MaxScanSize 200M # максимальный размер файла для развёртки архивов
MaxFileSize 100M # максимальный размер входного файла
MaxRecursion 10 # глубина рекурсии в архивах (снижаем с дефолтных 15)
MaxFiles 15000 # максимум файлов внутри одного архива
# --- Производительность движка
ConcurrentDatabaseReload yes # обновлять базу без остановки сканирования
Bytecode yes # обязательно - без этого пропустим новые угрозы
BytecodeSecurity TrustSigned # доверяем подписанным базам ClamAV
BytecodeTimeout 120000 # таймаут байткода в миллисекундах
# --- Исключения (обязательно!)
ExcludePath ^/proc/
ExcludePath ^/sys/
ExcludePath ^/dev/
ExcludePath ^/run/
ExcludePath ^/var/lib/docker/overlay
# --- Логирование
LogFile /var/log/clamav/clamav.log
LogFileMaxSize 10M
LogRotate yes
LogTime yes
ExtendedDetectionInfo yes # хеш и размер заражённого файла в логе
Параметр ConcurrentDatabaseReload заслуживает отдельного внимания. Без него каждое обновление сигнатур останавливает clamd на несколько секунд для перезагрузки базы - именно в этот момент сервер остаётся без защиты. С включённым параметром старая база остаётся активной до полной загрузки новой.
On-access сканирование через fanotify - настройка clamonacc без самоповреждений
clamonacc использует API fanotify для перехвата обращений к файлам на уровне ядра. При обнаружении вредоносного файла fanotify блокирует доступ к нему прямо в kernel-space, до того как процесс успевает прочитать содержимое.
Здесь кроется главная ловушка, из-за которой on-access сканирование получило репутацию инструмента, кладущего серверы. При включённом режиме блокировки clamonacc перехватывает абсолютно все события доступа к файлам - чтение, открытие, выполнение. На активной системе это создаёт огромное давление и может привести к тому, что система перестаёт отвечать.
Решений два: либо ограничить список директорий до минимально необходимого, либо переключиться в notify-only режим для некритичных путей.
OnAccessIncludePath не принимает / как допустимый путь - это сделано намеренно, чтобы не допустить блокировки системных процессов через fanotify. Защищать нужно только то, что действительно важно:
# Блок on-access настроек в /etc/clamav/clamd.conf
# --- Включаем on-access сканирование
ScanOnAccess yes
# --- Пути для мониторинга (только то, что реально нужно)
OnAccessIncludePath /home
OnAccessIncludePath /var/www
OnAccessIncludePath /tmp
OnAccessIncludePath /var/tmp
# --- Исключаем системные пользователи из триггеров fanotify
# (иначе clamd сам себя сканирует и создаёт бесконечный цикл)
OnAccessExcludeUname clamav
OnAccessExcludeUname root
# --- Режим блокировки (включаем только для критичных директорий)
OnAccessPrevention yes
# --- Ограничения для on-access сканирования
OnAccessMaxFileSize 20M # файлы больше этого размера не блокируются, только логируются
OnAccessMaxThreads 4 # отдельный пул потоков для on-access событий
# --- Дополнительные события (ядро >= 5.1)
OnAccessExtraScanning yes # перехватываем create и move-to события
Важный нюанс: clamonacc по умолчанию не передаёт файловые дескрипторы в clamd, из-за чего файлы в домашних директориях пользователей могут не сканироваться. Флаг --fdpass решает эту проблему.
Запускать clamonacc нужно с этим флагом и явным логом:
# Ручной запуск для проверки конфигурации
sudo clamonacc --fdpass -F --log=/var/log/clamav/clamonacc.log
# Если всё нормально - видим в логе:
# ClamInotif: watching '/home' (and all sub-directories)
# ClamInotif: watching '/var/www' (and all sub-directories)
Systemd-юнит для автоматического запуска с правильными параметрами:
# /etc/systemd/system/clamav-clamonacc.service
[Unit]
Description=ClamAV On-Access Scanner
Requires=clamav-daemon.service
After=clamav-daemon.service
[Service]
Type=simple
User=root
ExecStart=/usr/sbin/clamonacc --fdpass -F \
--log=/var/log/clamav/clamonacc.log \
--move=/var/quarantine
Restart=on-failure
RestartSec=30s
[Install]
WantedBy=multi-user.target
sudo mkdir -p /var/quarantine
sudo systemctl daemon-reload
sudo systemctl enable --now clamav-clamonacc
Параметр --move вместо --remove - принципиальный выбор. Удаление заражённых файлов опасно из-за ложных срабатываний, а их перемещение в карантин сохраняет возможность анализа инцидента.
freshclam и обновление сигнатур без рывков и просадок
По состоянию на начало 2024 года базы сигнатур ClamAV требуют минимум 1,6 ГБ свободной оперативной памяти. Во время периодического обновления кратковременно расходуется вдвое больше. Это значит, что на сервере с 4 ГБ RAM момент обновления базы - стресс для всей системы. Правильная конфигурация freshclam снижает этот стресс до минимума.
# /etc/clamav/freshclam.conf
# --- Частота проверок (максимум 12 раз в сутки по правилам зеркал ClamAV)
Checks 12 # каждые 2 часа - разумный баланс
# --- Логирование
UpdateLogFile /var/log/clamav/freshclam.log
LogFileMaxSize 5M
LogRotate yes
LogTime yes
LogVerbose no # выключаем подробный лог на продакшне
# --- Поведение при обновлении
MaxAttempts 5 # попыток соединения с зеркалом
ConnectTimeout 30
ReceiveTimeout 60
# --- Уведомление clamd о новой базе (clamd перезагружает сигнатуры)
NotifyClamd /etc/clamav/clamd.conf
Критически важная строка - NotifyClamd. Без неё freshclam скачает новую базу, но clamd продолжит работать со старой до следующей перезагрузки демона. Именно эта пара в связке с ConcurrentDatabaseReload yes в clamd.conf обеспечивает обновление сигнатур без окна незащищённости.
Убедиться, что обновление прошло и clamd подхватил новую базу:
# Версия загруженной базы
echo "VERSIONCOMMANDS" | socat - UNIX-CONNECT:/run/clamav/clamd.ctl
# Дата последнего обновления
sigtool --info /var/lib/clamav/daily.cld 2>/dev/null || \
sigtool --info /var/lib/clamav/daily.cvd
# → Build time: ... (смотрим, насколько свежая база)
# Принудительное обновление вручную
sudo freshclam --verbose
Как проверить, что on-access защита реально работает
Самый надёжный способ проверки - тестовый файл EICAR. Это стандартный безвредный файл, который все антивирусы обязаны детектировать как тестовую угрозу:
# Создаём тестовый файл в защищённой директории
cd /tmp
cat > eicar_test.txt << 'EOF'
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
EOF
# Если on-access работает в режиме блокировки - попытка прочитать файл завершится:
cat eicar_test.txt
# → bash: eicar_test.txt: Operation not permitted
# Это сообщение означает, что fanotify заблокировал доступ на уровне ядра
# В логе clamonacc должно появиться:
tail -f /var/log/clamav/clamonacc.log
# → /tmp/eicar_test.txt: Eicar-Signature FOUND
Параллельно полезно следить за нагрузкой, которую создаёт on-access сканирование в реальных условиях:
# Мониторинг очереди clamd в реальном времени (встроенный инструмент)
clamdtop
# Проверяем статистику через сокет
echo "STATS" | socat - UNIX-CONNECT:/run/clamav/clamd.ctl
# → POOLS: 1 / STATE: valid primary / THREADS: live 3 idle 13 max 16 / QUEUE: 0 items
# Следим за нагрузкой clamonacc на систему
pidstat -p $(pgrep clamonacc) 1 10
Если в выводе QUEUE постоянно показывает ненулевые значения - очередь не успевает разгребаться. Решения: увеличить MaxThreads, сузить список OnAccessIncludePath, или повысить OnAccessMaxFileSize, чтобы крупные файлы не проходили через синхронную блокировку.
Профили конфигурации под разные типы серверов
Универсальной конфигурации ClamAV не существует - слишком разные нагрузки. Почтовый шлюз видит тысячи мелких вложений в час, файловый сервер хранит гигабайтные архивы, веб-сервер получает загрузки от пользователей. Каждый сценарий диктует свои приоритеты.
Для почтового шлюза (Postfix + ClamAV через clamav-milter) on-access сканирование обычно не нужно совсем - достаточно потоковой проверки через INSTREAM. Здесь критичен StreamMaxLength, который должен совпадать с лимитом размера вложений в MTA, и высокий MaxThreads для параллельной обработки писем.
Для веб-сервера с пользовательскими загрузками on-access сканирование на директорию загрузок - правильный выбор, но OnAccessPrevention должен быть включён только там. Остальная файловая система работает в notify-only режиме, чтобы не создавать задержек при отдаче статики.
Для файлового сервера с большими архивами следует снизить MaxRecursion до 5-7 и явно ограничить MaxScanSize - иначе один многоуровневый zip-файл может занять поток сканирования на минуты. Разбирать 500-мегабайтный архив с 10 уровнями вложенности ради поиска трояна - сомнительная инвестиция ресурсов при регулярной фоновой нагрузке.
Честный итог выглядит так: ClamAV с on-access сканированием - это не простая кнопка "включить защиту". Это инструмент, который требует понимания собственной нагрузки, разумного выбора защищаемых путей и постоянного наблюдения за очередью clamd. Те, кто настроил его правильно, получают реальную защиту файловой системы с минимальным влиянием на производительность. Те, кто включил дефолты на нагруженном сервере - получают опыт, после которого хочется всё это понять наконец по-настоящему.