An Ansible role for managing ClamAV antivirus on Debian-based systems. This role provides flexible malware protection through scheduled scanning, real-time on-access monitoring, or both.
- Scheduled Scanning: Automated periodic scans with configurable schedules
- On-Access Monitoring: Real-time file scanning using
clamonacc - Quarantine Management: Automatic isolation of infected files
- Email Notifications: Alert on malware detection
- Log Rotation: Automatic log management with configurable retention
- Zabbix Monitoring: Integration with Zabbix agent for monitoring
- Flexible Exclusions: Define paths and file extensions to skip
- Ansible 2.12 or higher
- Debian-based operating system:
- Debian 11 (Bullseye)
- Debian 12 (Bookworm)
- Debian 13 (Trixie)
- Ubuntu 22.04 (Jammy)
- Ubuntu 24.04 (Noble)
ansible-galaxy install oxess.clamavgit clone https://github.com/oxess/ansible-clamav.git roles/oxess.clamav| Variable | Default | Description |
|---|---|---|
clamav_mode |
"scheduled" |
Scanning mode: scheduled, on-access, or both |
| Variable | Default | Description |
|---|---|---|
clamav_scan_directories |
["/var/www"] |
List of directories to scan |
clamav_exclude_directories |
["/var/www/prestashop/var/cache", "/var/www/prestashop/vendor"] |
Directories to exclude from scanning |
clamav_exclude_extensions |
[".log", ".sql"] |
File extensions to exclude |
Scheduled scanning uses systemd timers for reliable, modern scheduling with security hardening.
| Variable | Default | Description |
|---|---|---|
clamav_scheduled_enabled |
true |
Enable/disable scheduled scanning |
clamav_scheduled_hour |
"3" |
Hour to run scan (0-23) |
clamav_scheduled_minute |
"0" |
Minute to run scan (0-59) |
clamav_scheduled_weekday |
"*" |
Day(s) to run: * (daily), 0-6 (specific day), "0,3" (multiple) |
clamav_scheduled_randomized_delay |
"5min" |
Random delay to spread load across systems |
clamav_scheduled_oncalendar |
(auto) | Override with explicit systemd OnCalendar format |
clamav_scheduled_timeout |
(none) | Optional maximum scan duration (e.g., "2h") |
Note: The legacy variables (hour, minute, weekday) are automatically converted to systemd's OnCalendar format. You can override this by setting clamav_scheduled_oncalendar directly using systemd.time(7) syntax.
OnCalendar examples:
"*-*-* 03:00:00"- Daily at 3 AM"Mon,Wed,Fri 02:30:00"- Mon/Wed/Fri at 2:30 AM"weekly"- Weekly on Monday at midnight
| Variable | Default | Description |
|---|---|---|
clamav_on_access_enabled |
false |
Enable/disable on-access scanning |
clamav_on_access_mount_path |
"/var/www" |
Path to monitor for file access |
clamav_on_access_include_pattern |
"" |
Pattern for files to include |
clamav_on_access_exclude_uid |
"" |
UID to exclude (e.g., www-data) |
| Variable | Default | Description |
|---|---|---|
clamav_max_file_size |
"100M" |
Maximum file size to scan |
clamav_max_scan_size |
"400M" |
Maximum scan size for archives |
clamav_max_recursion |
16 |
Maximum archive recursion depth |
clamav_max_files |
10000 |
Maximum files in archive to scan |
| Variable | Default | Description |
|---|---|---|
clamav_freshclam_checks_per_day |
12 |
Update checks per day (12 = every 2 hours) |
clamav_freshclam_database_mirror |
"database.clamav.net" |
Mirror for virus definitions |
| Variable | Default | Description |
|---|---|---|
clamav_notify_email |
"" |
Email for notifications (empty = disabled) |
clamav_log_file |
"/var/log/clamav/scan.log" |
Path to scan log file |
| Variable | Default | Description |
|---|---|---|
clamav_quarantine_enabled |
true |
Enable quarantine for infected files |
clamav_quarantine_dir |
"/var/quarantine" |
Quarantine directory path |
| Variable | Default | Description |
|---|---|---|
clamav_logrotate_enabled |
true |
Enable log rotation |
clamav_log_retention_days |
30 |
Days to retain logs |
| Variable | Default | Description |
|---|---|---|
clamav_zabbix_enabled |
"auto" |
Zabbix integration: auto, true, or false |
clamav_zabbix_agent_conf_dir |
"/etc/zabbix/zabbix_agentd.conf.d" |
Zabbix agent config directory |
clamav_zabbix_agent_service |
"zabbix-agent" |
Zabbix agent service name |
None.
Protect a web application by scanning specified directories on a schedule. Useful for detecting malware uploaded through web forms or compromised files.
---
- name: Configure ClamAV for web application
hosts: webservers
become: true
vars:
# Scheduled scanning mode
clamav_mode: "scheduled"
# Directories to scan
clamav_scan_directories:
- "/var/www/myapp/uploads"
- "/var/www/myapp/public"
- "/home/deploy/shared"
# Exclude cache and vendor directories (they change frequently)
clamav_exclude_directories:
- "/var/www/myapp/var/cache"
- "/var/www/myapp/vendor"
- "/var/www/myapp/node_modules"
# Exclude common safe file types
clamav_exclude_extensions:
- ".log"
- ".sql"
- ".txt"
# Run scan daily at 2:30 AM
clamav_scheduled_hour: "2"
clamav_scheduled_minute: "30"
clamav_scheduled_weekday: "*"
# Enable quarantine
clamav_quarantine_enabled: true
clamav_quarantine_dir: "/var/quarantine/clamav"
# Send alerts to admin
clamav_notify_email: "admin@example.com"
# Keep logs for 60 days
clamav_log_retention_days: 60
roles:
- role: oxess.clamavWeekly scanning example (every Sunday at 4 AM):
---
- name: Weekly ClamAV scan
hosts: webservers
become: true
vars:
clamav_mode: "scheduled"
clamav_scan_directories:
- "/var/www"
clamav_scheduled_hour: "4"
clamav_scheduled_minute: "0"
clamav_scheduled_weekday: "0" # Sunday
roles:
- role: oxess.clamavReal-time protection that scans files as they are accessed. Ideal for high-security environments where immediate detection is critical.
---
- name: Configure ClamAV on-access protection
hosts: fileservers
become: true
vars:
# Enable on-access monitoring
clamav_mode: "on-access"
clamav_on_access_enabled: true
# Monitor the main application directory
clamav_on_access_mount_path: "/var/www/myapp"
# Exclude web server user from scanning (prevents performance issues)
# Get UID with: id -u www-data
clamav_on_access_exclude_uid: "33"
# Exclude directories that change frequently
clamav_exclude_directories:
- "/var/www/myapp/cache"
- "/var/www/myapp/sessions"
- "/var/www/myapp/tmp"
- "/var/www/myapp/vendor"
- "/var/www/myapp/node_modules"
# Exclude safe file types
clamav_exclude_extensions:
- ".log"
- ".pid"
- ".sock"
- ".lock"
# Quarantine infected files immediately
clamav_quarantine_enabled: true
clamav_quarantine_dir: "/var/quarantine"
roles:
- role: oxess.clamavCombined mode (both scheduled and on-access):
---
- name: Maximum protection with both scanning modes
hosts: critical_servers
become: true
vars:
# Enable both modes
clamav_mode: "both"
# On-access settings
clamav_on_access_enabled: true
clamav_on_access_mount_path: "/var/www"
# Scheduled scan settings (nightly full scan)
clamav_scheduled_enabled: true
clamav_scheduled_hour: "3"
clamav_scheduled_minute: "0"
# Common exclusions
clamav_exclude_directories:
- "/var/www/cache"
- "/var/www/vendor"
roles:
- role: oxess.clamavMonitor ClamAV health and scan results through Zabbix. Get alerts when infections are detected or services fail.
---
- name: Configure ClamAV with Zabbix monitoring
hosts: monitored_servers
become: true
vars:
clamav_mode: "scheduled"
clamav_scan_directories:
- "/var/www"
- "/home"
# Enable Zabbix integration
# "auto" - enables if zabbix-agent is detected
# "true" - always enable
# "false" - disable
clamav_zabbix_enabled: "auto"
# Zabbix agent configuration (adjust if using non-standard paths)
clamav_zabbix_agent_conf_dir: "/etc/zabbix/zabbix_agentd.conf.d"
clamav_zabbix_agent_service: "zabbix-agent"
# Schedule for frequent scans (better monitoring data)
clamav_scheduled_hour: "*/6" # Every 6 hours
clamav_scheduled_minute: "0"
roles:
- role: oxess.clamavAfter deployment, these monitoring items become available:
| UserParameter | Description | Values |
|---|---|---|
clamav.scan.infected_count |
Infected files from last scan | Integer (0 = clean) |
clamav.scan.last_run |
Timestamp of last scan | Unix epoch |
clamav.scan.running |
Scan currently in progress | 1 = running, 0 = idle |
clamav.service.clamd |
ClamAV daemon status | 1 = active, 0 = inactive |
clamav.service.freshclam |
Freshclam service status | 1 = active, 0 = inactive |
clamav.definitions.age |
Virus definitions age | Seconds since last update |
Create triggers for:
# Alert if infected files detected
{host:clamav.scan.infected_count.last()}>0
# Alert if ClamAV daemon is down
{host:clamav.service.clamd.last()}=0
# Alert if freshclam is down
{host:clamav.service.freshclam.last()}=0
# Alert if virus definitions are older than 24 hours
{host:clamav.definitions.age.last()}>86400
# Alert if no scan has run in 48 hours
{host:clamav.scan.last_run.now()}-{host:clamav.scan.last_run.last()}>172800
A comprehensive example combining all features for a production environment:
---
- name: Production ClamAV configuration
hosts: production_web
become: true
vars:
# Use scheduled scanning (less performance impact)
clamav_mode: "scheduled"
# Scan user content directories
clamav_scan_directories:
- "/var/www/app/public/uploads"
- "/var/www/app/storage"
- "/home/deploy"
# Exclude framework and build directories
clamav_exclude_directories:
- "/var/www/app/vendor"
- "/var/www/app/node_modules"
- "/var/www/app/storage/framework/cache"
- "/var/www/app/storage/framework/sessions"
- "/var/www/app/storage/framework/views"
# Exclude common safe extensions
clamav_exclude_extensions:
- ".log"
- ".sql"
- ".lock"
- ".cache"
# Daily scan at 3 AM
clamav_scheduled_enabled: true
clamav_scheduled_hour: "3"
clamav_scheduled_minute: "0"
clamav_scheduled_weekday: "*"
# Quarantine settings
clamav_quarantine_enabled: true
clamav_quarantine_dir: "/var/quarantine"
# Email alerts
clamav_notify_email: "security@example.com"
# Logging
clamav_log_file: "/var/log/clamav/scan.log"
clamav_logrotate_enabled: true
clamav_log_retention_days: 90
# Zabbix monitoring
clamav_zabbix_enabled: "auto"
# Performance tuning
clamav_max_file_size: "50M"
clamav_max_scan_size: "200M"
# Update virus definitions every 2 hours
clamav_freshclam_checks_per_day: 12
roles:
- role: oxess.clamavThe role supports the following tags for selective execution:
| Tag | Description |
|---|---|
clamav |
Run all ClamAV tasks |
clamav:install |
Install ClamAV packages only |
clamav:configure |
Configure ClamAV daemon only |
clamav:scheduled |
Configure scheduled scanning only |
clamav:on-access |
Configure on-access scanning only |
clamav:logrotate |
Configure log rotation only |
clamav:zabbix |
Configure Zabbix monitoring only |
antivirus |
Alias for all ClamAV tasks |
# Install and configure only (skip scheduled/on-access setup)
ansible-playbook site.yml --tags "clamav:install,clamav:configure"
# Update Zabbix monitoring configuration only
ansible-playbook site.yml --tags "clamav:zabbix"
# Configure scheduled scanning without touching other settings
ansible-playbook site.yml --tags "clamav:scheduled"The role includes comprehensive Molecule tests.
pip install -r requirements-test.txt# Run full test suite on all platforms
molecule test
# Test on a specific platform
molecule test --platform-name debian-bookworm
molecule test --platform-name ubuntu-noble
# Development workflow (faster iteration)
molecule create # Create test containers
molecule converge # Apply the role
molecule verify # Run verification tests
molecule destroy # Clean updebian-bullseye(Debian 11)debian-bookworm(Debian 12)debian-trixie(Debian 13)ubuntu-jammy(Ubuntu 22.04)ubuntu-noble(Ubuntu 24.04)
The scheduled scan uses a systemd timer (clamav-scan.timer) and service (clamav-scan.service).
# View timer status and next scheduled run
systemctl status clamav-scan.timer
# List all timers including clamav-scan
systemctl list-timers clamav-scan.timer
# Show detailed timer configuration
systemctl show clamav-scan.timer --property=TimersCalendar# Trigger an immediate scan (without waiting for timer)
systemctl start clamav-scan.service
# Watch the scan progress
journalctl -u clamav-scan.service -f# View systemd journal logs
journalctl -u clamav-scan.service
# View the scan log file
tail -f /var/log/clamav/scan.log# Temporarily disable the timer
systemctl stop clamav-scan.timer
# Re-enable the timer
systemctl start clamav-scan.timer
# Check if timer is enabled at boot
systemctl is-enabled clamav-scan.timerFreshclam fails to update
Check network connectivity and mirror availability:
freshclam -vScheduled scan not running
Check the timer status and logs:
systemctl status clamav-scan.timer
systemctl status clamav-scan.service
journalctl -u clamav-scan.service --since "1 hour ago"On-access scanning not working
Verify the clamonacc service:
systemctl status clamonacc
journalctl -u clamonacc -fHigh CPU usage during scans
Reduce scan scope or add exclusions:
clamav_exclude_directories:
- "/var/cache"
- "/tmp"
clamav_max_file_size: "25M"You can also set a timeout to limit scan duration:
clamav_scheduled_timeout: "1h"Zabbix items not appearing
Restart Zabbix agent after role deployment:
systemctl restart zabbix-agent
zabbix_agentd -t clamav.service.clamd- The quarantine directory (
clamav_quarantine_dir) should have restricted permissions - Review excluded paths regularly to ensure malware can't hide in excluded locations
- Email notifications require a properly configured MTA (sendmail/postfix)
- On-access scanning requires root privileges for the clamonacc service
- The scheduled scan service runs with systemd security hardening:
PrivateTmp=true- Isolated temporary directoryProtectSystem=strict- Read-only system directoriesProtectHome=read-only- Read-only home directoriesNoNewPrivileges=true- Prevents privilege escalation
MIT
This Ansible Role was created by Mikołaj Jeziorny in 2025. Contact with me or open an issue if you have any questions or suggestions.