ClamAV is the open-source antivirus engine used on Linux mail servers, file servers and web hosts. On a server it’s mostly used to scan files that come from outside: uploads, email attachments, shared folders, and website files after a suspected hack. Here’s how to install it, keep it updated and run useful scans without overloading a small VPS.

Install

Debian/Ubuntu:

sudo apt update
sudo apt install clamav clamav-daemon

RHEL family (EPEL):

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

Update the virus signatures

freshclam downloads the signature databases. On Debian and Ubuntu, the clamav-freshclam service updates them automatically:

sudo systemctl status clamav-freshclam

To update manually, stop the service first, since both can’t run at once:

sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl start clamav-freshclam

On RHEL-family systems, enable updates with sudo systemctl enable --now clamav-freshclam, or run freshclam from a timer. Remove the Example line in /etc/freshclam.conf if present.

Scan files: clamscan

clamscan -r --infected /var/www                     # recursive, show only infected files
clamscan -r -i --exclude-dir='^/var/www/.*/cache' /var/www
clamscan -r -i --log=/var/log/clamav/www-scan.log /var/www

Useful options:

  • -r — recursive.
  • -i — print only infected files.
  • --move=/root/quarantine — move detections to quarantine. Review before deleting.
  • --max-filesize=50M --max-scansize=200M — skip huge files.

clamscan loads the whole signature database each run, which takes 10–30 seconds and about 1 GB of RAM. On a 2 GB VPS, that’s significant. Scan at quiet times, at low priority:

nice -n 19 ionice -c3 clamscan -r -i /var/www

Faster scans: clamd

The daemon keeps signatures in memory, so scans start instantly. It permanently uses about 1–1.5 GB of RAM, so it’s worthwhile on servers with 4 GB+ that scan often, such as mail servers:

sudo systemctl enable --now clamav-daemon       # 'clamd@scan' on RHEL
clamdscan --fdpass -m -i /var/www               # multi-threaded scan via the daemon

--fdpass lets the daemon read files your user can access.

Schedule a daily scan

sudo tee /etc/cron.daily/clamscan-www > /dev/null <<'EOF'
#!/bin/sh
LOG=/var/log/clamav/www-$(date +%F).log
nice -n 19 ionice -c3 clamscan -r -i --log="$LOG" /var/www /home > /dev/null 2>&1
if grep -q 'Infected files: [1-9]' "$LOG"; then
  mail -s "ClamAV: infected files on $(hostname)" [email protected] < "$LOG"
fi
EOF
sudo chmod +x /etc/cron.daily/clamscan-www

The mail step needs a working MTA. Alternatively, send the alert to a webhook. A systemd timer works just as well. See systemd timers.

Scan uploads as they arrive

For apps that accept uploads, scan each file before storing it. Call clamdscan --fdpass file from the app, or use a library that talks to clamd’s socket (PHP, Python and Node libraries exist). Reject or quarantine the file on detection.

Mail servers integrate ClamAV through amavis, rspamd or clamav-milter, scanning every attachment.

What ClamAV is good, and not so good, at

Good at:

  • known malware in uploaded files and attachments (Windows malware, macro documents, known PHP shells);
  • keeping infected files from being redistributed to your users.

Limited at:

  • new or obfuscated PHP backdoors and injected JavaScript on hacked websites. Signature coverage for web malware is weaker. Third-party signature sets (such as those from Linux Malware Detect, or commercial feeds) improve detection;
  • rootkits and system compromise. Use dedicated tools. See rkhunter and chkrootkit;
  • real-time protection on servers. On-access scanning (clamonacc) exists but is resource-heavy.

If ClamAV finds something on your website

  1. Don’t just delete the file. Find out how it got there: outdated plugins, weak passwords, writable upload directories that execute PHP.
  2. Compare files with a clean copy (WordPress core: wp core verify-checksums). See WP-CLI.
  3. Check for other changes: recently modified files (find /var/www -mtime -7 -name '*.php'), new admin users, cron jobs.
  4. Patch the hole, rotate passwords and keys, and restore from a clean backup if in doubt.
  5. Harden it: disable PHP execution in upload folders, and keep software updated. See WordPress hardening.

Quick reference

Task Command
Install apt install clamav clamav-daemon
Update signatures freshclam (service: clamav-freshclam)
Scan directory clamscan -r -i /path
Low priority nice -n19 ionice -c3 clamscan …
Via daemon clamdscan --fdpass -m -i /path
Quarantine --move=/root/quarantine

Related: Lynis security audit and Linux server hardening.

  • Security
  • Linux
  • Malware