ClamAV is an open-source antivirus engine widely used on Linux servers to detect malware in files destined for Windows users — such as email attachments, uploaded documents, and shared network storage. While Linux systems are largely immune to the Windows malware that ClamAV detects, running it is a responsible practice wherever Linux servers act as intermediaries for files that Windows or macOS clients will open. On RHEL 9, ClamAV is available through the EPEL repository and can be configured for both on-demand and real-time scanning. This tutorial covers installation, virus database updates, scheduled scans, and on-access scanning.

Prerequisites

  • A RHEL 9 server with root or sudo access
  • EPEL repository enabled (sudo dnf install -y epel-release)
  • Internet access on the server for downloading virus definitions

Step 1 — Install ClamAV and the Updater

sudo dnf install -y epel-release
sudo dnf install -y clamav clamav-update clamd

Verify the installed versions:

clamscan --version
freshclam --version

Step 2 — Update the Virus Definition Database

ClamAV’s signature database must be current before the first scan. The freshclam utility downloads updates from the ClamAV mirrors. On a freshly installed system, SELinux may need to allow the freshclam service, so temporarily run it manually first:

# Remove the example config comment that blocks freshclam
sudo sed -i 's/^Example$/#Example/' /etc/freshclam.conf

# Run a manual update
sudo freshclam

You should see output confirming that main.cvd, daily.cvd, and bytecode.cvd were downloaded or are up to date. Enable the freshclam service for automatic background updates:

sudo systemctl enable --now clamav-freshclam
sudo systemctl status clamav-freshclam

Step 3 — Run an On-Demand Scan

Use clamscan for immediate, one-off directory scans. The -r flag enables recursive scanning, --infected limits output to infected files only, and --remove automatically deletes detected threats (use with caution — prefer --move=/quarantine in production).

# Scan home directories and report infected files
sudo clamscan -r /home --infected --log=/var/log/clamav/manual-scan.log

# Move infected files to a quarantine directory instead of deleting
sudo mkdir -p /quarantine
sudo clamscan -r /var/www/html --infected --move=/quarantine 
  --log=/var/log/clamav/webscan.log

Step 4 — Configure and Enable the ClamAV Daemon (clamd)

For higher performance scheduled scans, run clamd as a persistent daemon so signature databases stay loaded in memory. Edit the scan configuration:

sudo sed -i 's/^Example$/#Example/' /etc/clamd.d/scan.conf

# Set the socket path (required)
sudo sed -i 's|^#LocalSocket .*|LocalSocket /run/clamd.scan/clamd.sock|' 
  /etc/clamd.d/scan.conf

Enable and start the daemon:

sudo systemctl enable --now clamd@scan
sudo systemctl status clamd@scan

Use clamdscan (the daemon client) for faster scans after the daemon is running:

sudo clamdscan -r /home --infected

Step 5 — Schedule Automated Daily Scans

Create a simple shell script and schedule it with a systemd timer (preferred over cron on RHEL 9) or a cron job.

sudo nano /usr/local/bin/clamav-daily-scan.sh
#!/bin/bash
LOGFILE=/var/log/clamav/daily-$(date +%F).log
QUARANTINE=/quarantine

mkdir -p "$QUARANTINE"
/usr/bin/clamdscan -r /home /var/www/html 
  --infected 
  --move="$QUARANTINE" 
  --log="$LOGFILE"

# Email report if infected files were found
if grep -q "Infected files: [^0]" "$LOGFILE"; then
  mail -s "ClamAV Alert: Infected files found on $(hostname)" 
    root < "$LOGFILE"
fi
sudo chmod +x /usr/local/bin/clamav-daily-scan.sh

Add a cron entry to run the scan at 2 AM daily:

echo "0 2 * * * root /usr/local/bin/clamav-daily-scan.sh" 
  | sudo tee /etc/cron.d/clamav-daily

Step 6 — Enable On-Access Scanning with fanotify

ClamAV supports real-time on-access scanning using the Linux fanotify API. Files are scanned as they are opened or executed. Enable it in the scan config:

sudo nano /etc/clamd.d/scan.conf

Add or uncomment these directives:

ScanOnAccess yes
OnAccessMountPath /home
OnAccessMountPath /var/www/html
OnAccessExcludeUname clamav
OnAccessPrevention yes

Restart the daemon to apply:

sudo systemctl restart clamd@scan

Note: OnAccessPrevention yes blocks access to infected files in real time. Test this carefully in a staging environment before enabling it on production systems, as false positives could block legitimate files.

Conclusion

ClamAV on RHEL 9 provides a layered approach to malware detection: freshclam keeps virus definitions current, clamd offers fast daemon-based scanning, automated cron jobs ensure nothing is missed overnight, and fanotify on-access scanning catches threats in real time. While the Linux malware landscape differs significantly from Windows, any server that handles file uploads, serves email, or acts as a file share for mixed-OS environments benefits from ClamAV’s presence. Regularly review scan logs in /var/log/clamav/ and keep the freshclam service running to maintain up-to-date protection.

Next steps: How to Configure SELinux on RHEL 9, How to Harden SSH on RHEL 9, and How to Configure Postfix for Outbound Email Alerts on RHEL 9.