ClamAV, a surprisingly effective malware scanner, is often dismissed as too slow for modern Linux systems, but its real power lies in its deep integration and configurability for scheduled, automated scans.

Let’s see it in action. Imagine you’ve just deployed a new web server and want to ensure no malicious files are creeping in. You can trigger an on-demand scan of a specific directory like this:

clamscan -r /var/www/html

The output will look something like this, listing each file and whether it’s clean or infected:

/var/www/html/index.html: OK
/var/www/html/malicious.php: FOUND
/var/www/html/images/logo.png: OK

----------- SCAN SUMMARY -----------
Known viruses: 8765432
Engine version: 0.103.6
Scanned directories: 150
Scanned files: 2345
Infected files: 1
Data scanned: 123.45 MB
Data read: 567.89 MB (ratio 0.22:1.00)
Time: 120.567 sec (0 m 120 s)

To make this truly useful, you’ll want to automate it. This involves installing ClamAV, configuring its update schedule, and then setting up a cron job for regular scans.

First, install ClamAV and its freshclam utility for signature updates. On Debian/Ubuntu systems:

sudo apt update
sudo apt install clamav clamav-daemon

On RHEL/CentOS/Fedora systems:

sudo yum install epel-release
sudo yum install clamav clamav-update

Next, configure freshclam to update the virus definitions. This is crucial. Without up-to-date signatures, ClamAV is blind. Edit the freshclam.conf file (usually located at /etc/clamav/freshclam.conf) to ensure it’s not running in daemon mode if you’re only using it for scheduled scans, and to specify a mirror if you encounter issues. A common configuration might look like this:

# Comment out the Daemon setting if you don't want it running as a service
# Daemon

# Uncomment and set a specific mirror if needed
# DefaultMirror mirror.example.com

Then, start and enable the freshclam service to ensure definitions are downloaded regularly:

sudo systemctl start clamav-freshclam
sudo systemctl enable clamav-freshclam

Now, to scan your entire system, you’ll typically want to exclude certain directories to avoid false positives and speed up scans. Common exclusions include /proc, /sys, /dev, and /run. You can define these in /etc/clamav/clamd.conf (if running clamd as a daemon) or pass them directly to clamscan. For automated scans via cron, it’s cleaner to create a script.

Here’s a basic scan script (/usr/local/bin/daily_clamscan.sh):

#!/bin/bash

LOGFILE="/var/log/clamav/daily_scan.log"
SCAN_DIRS="/home /var/www /opt"
EXCLUDE_DIRS="--exclude-dir=/proc --exclude-dir=/sys --exclude-dir=/dev --exclude-dir=/run --exclude-dir=/var/log/clamav"

echo "Starting ClamAV scan on $(date)" >> $LOGFILE

clamscan -r $EXCLUDE_DIRS $SCAN_DIRS --infected --log=$LOGFILE --move=/tmp/infected_files >> $LOGFILE

echo "ClamAV scan finished on $(date)" >> $LOGFILE
echo "----------------------------------------" >> $LOGFILE

Make the script executable:

sudo chmod +x /usr/local/bin/daily_clamscan.sh

Finally, schedule this script using cron. To run it daily at 3 AM:

sudo crontab -e

Add the following line:

0 3 * * * /usr/local/bin/daily_clamscan.sh

This setup allows ClamAV to continuously update its signatures and perform regular, automated scans of your critical directories, moving any detected malware to a quarantine directory (/tmp/infected_files in this example) for further inspection. The --infected flag ensures only infected files are reported, and --log directs output to a dedicated file.

What most people don’t realize is how clamd (the daemon) can significantly speed up scans when running continuously. Instead of clamscan loading the virus database into memory for every scan, clamd keeps it resident, making subsequent scans much faster. To enable this, you’d edit /etc/clamav/clamd.conf, uncomment LocalSocket and PidFile, and then use clamdscan instead of clamscan in your script, pointing it to the LocalSocket specified in clamd.conf.

The next logical step is to integrate ClamAV with your mail server or web application firewall for real-time scanning.

Want structured learning?

Take the full Cdk course →