At 2:00 AM, PagerDuty alerts go off non-stop. The WordPress web server’s CPU spikes to 100%, and outbound traffic hits 250 Mbps. An attacker just dropped a webshell into the wp-content/uploads directory to download and run a hidden Monero miner. In this scenario, ClamAV is the most practical open-source solution: available directly from the Ubuntu repository, completely free, and capable of detecting infected files immediately.
Quick Start: Installation and Scanning in 5 Minutes
If your server is experiencing unusual lag and you need to inspect suspicious files right away, open your terminal and run the following commands:
# 1. Update repositories and install ClamAV packages
sudo apt update
sudo apt install -y clamav clamav-daemon
# 2. Stop the freshclam service to prevent process lock conflicts
sudo systemctl stop clamav-freshclam
# 3. Fetch the latest virus signatures from Cisco Talos
sudo freshclam
# 4. Re-enable and restart the signature auto-update process
sudo systemctl start clamav-freshclam
sudo systemctl enable clamav-freshclam
# 5. Recursively scan the web directory, displaying only infected files
sudo clamscan -r -i /var/www/html
In the command above, the -r (recursive) flag scans deep into all subdirectories. The -i (infected) flag filters out hundreds of thousands of clean file log entries, printing only the files containing backdoors or trojans. For additional defense against hidden trojans and modified system binaries, you can also verify system integrity with debsums.
Understanding ClamAV Core Components
Once the fire is put out, it is important to understand how ClamAV actually works. This helps you avoid server crashes caused by memory exhaustion or disk I/O bottlenecks. Beyond immediate malware cleanup, running a comprehensive security audit with Lynis will help identify system weaknesses and harden your environment.
1. Comparing clamscan vs clamdscan
These two commands serve entirely different use cases:
- clamscan (Standalone CLI): Each time it runs, it spends roughly 20–30 seconds just loading the entire virus signature database from disk into RAM. Once the scan finishes, the process terminates and frees the memory. This is handy for ad-hoc checks, but heavy on I/O and CPU if executed frequently.
- clamdscan (Client/Server via Socket): Relies on
clamav-daemon, which permanently keeps the database preloaded in RAM. When runningclamdscan, the command simply sends the target file path through a local UNIX socket (/run/clamav/clamd.ctl) for the daemon to scan. Scanning speed is 5 to 10 times faster thanclamscan.
2. Freshclam: Signature Update Mechanism
ClamAV’s malware signature database is maintained hourly by Cisco Talos. The configuration file is located at /etc/clamav/freshclam.conf. By default, the clamav-freshclam daemon checks for updates 24 times a day (once every hour) over HTTPS.
3. Fixing the Error: “freshclam is locked by another process”
If you run sudo freshclam right after installation, you will almost certainly encounter this error:
ERROR: /var/log/clamav/freshclam.log is locked by another process
ERROR: Problem database update failed.
The reason is simple: immediately after apt completes installation, Ubuntu automatically launches the clamav-freshclam service in the background. This service acquires an exclusive lock on both the log file and the database. To update manually, simply stop the service first:
sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl start clamav-freshclam
Automating Scans and Email Alerts with Cron Jobs
Automatically quarantining infected files is a critical step to prevent malware from spreading before you can intervene. To block malicious activity and exploit attempts before backdoors are ever uploaded, consider deploying CrowdSec as an intrusion prevention system.
1. Creating a Quarantine Directory
Avoid using the --remove flag to delete files immediately, as this can lead to data loss from false positives (clean code mistakenly identified as malicious). Instead, move suspicious files to an isolated directory with strict permissions:
sudo mkdir -p /var/quarantine
sudo chmod 700 /var/quarantine
2. Writing an Automation Bash Script
Create an executable script at /usr/local/bin/clamav-auto-scan.sh:
sudo nano /usr/local/bin/clamav-auto-scan.sh
Add the following script content (requires the server to have mailutils or another mail utility configured):
#!/bin/bash
SCAN_TARGET="/var/www /home /tmp"
LOG_FILE="/var/log/clamav/daily-scan.log"
QUARANTINE_DIR="/var/quarantine"
DATE=$(date +"%Y-%m-%d %H:%M:%S")
echo "=== ClamAV scan started at: $DATE ===" >> "$LOG_FILE"
# Recursively scan, quarantine infected files, and skip virtual filesystems
clamscan -r -i \
--move="$QUARANTINE_DIR" \
--exclude-dir="^/sys" \
--exclude-dir="^/proc" \
--exclude-dir="^/dev" \
--log="$LOG_FILE" \
$SCAN_TARGET
INFECTED_COUNT=$(grep "Infected files:" "$LOG_FILE" | tail -n 1 | awk '{print $3}')
if [ "$INFECTED_COUNT" -gt 0 ]; then
echo "[ALERT] $INFECTED_COUNT infected file(s) detected! Check immediately at $QUARANTINE_DIR" | mail -s "[ALERT] Virus detected on $(hostname)" [email protected]
fi
Grant execute permissions to the newly created script:
sudo chmod +x /usr/local/bin/clamav-auto-scan.sh
3. Scheduling a Nightly Cron Job
Open the root crontab with sudo crontab -e and add the scan schedule to run at 3:00 AM:
0 3 * * * /usr/local/bin/clamav-auto-scan.sh > /dev/null 2>&1
Production Resource Optimization Tips
Running antivirus software on a Linux server requires careful planning to prevent performance degradation on user-facing web services. Utilizing real-time system monitoring with Netdata helps you keep a close eye on CPU and I/O metrics while resource-intensive scans execute.
1. Lower Process Priority with nice and ionice
Scanning compressed .zip archives or directories with millions of small files (such as framework caches) can spike CPU usage to 100% and saturate disk I/O. Reduce the scan process priority to the lowest level:
nice -n 19 ionice -c 3 clamscan -r -i /var/www
This configuration instructs the OS scheduler to prioritize CPU for Nginx/PHP-FPM first. Additionally, disk bandwidth is allocated to ClamAV only when the disk is completely idle (Idle class – -c 3).
2. Managing RAM Overhead for clamav-daemon
ClamAV’s detection database currently contains over 8.5 million virus signatures. When loaded into memory, clamd actively consumes between 1.1 GB and 1.4 GB of RAM. On a VPS with only 1 GB or 2 GB of RAM, the Linux kernel’s OOM Killer will likely terminate MySQL to reclaim memory.
For servers with less than 2 GB of RAM:
- Completely disable
clamav-daemon(sudo systemctl disable --now clamav-daemon). - Create a swap file of at least 2 GB to buffer memory spikes.
- Run only standalone
clamscanvia cron jobs during off-peak hours (between 2:00 AM and 4:00 AM).
3. Always Exclude Virtual Filesystems
If scanning the entire disk starting from the root directory (/), you must add exclusion flags: --exclude-dir="^/proc", --exclude-dir="^/sys", and --exclude-dir="^/dev". These directories contain virtual files created by the kernel in RAM. Scanning them traps ClamAV in infinite loops, saturates I/O, and can easily freeze your server.

