Introduction
Most SMB file servers, mail relays, and upload endpoints run completely unscanned — the assumption is that "the endpoint AV will catch it" when a user opens the file later. By then the malicious attachment has already sat in a shared folder, been forwarded to three other mailboxes, or been served back out through a web app.
ClamAV is a free, open-source antivirus engine built specifically for this gap: server-side, scriptable, signature-based scanning of files in transit or at rest. It's not a replacement for a modern EDR agent on endpoints, but it's an excellent last line of defense on file shares, mail gateways, and upload pipelines where an EDR agent will never run.
This guide covers installing ClamAV, running it as a persistent daemon (clamd) for fast repeated scans, scheduling signature updates and full scans, quarantining infected files automatically, and verifying the whole pipeline with a safe test file.
Prerequisites
Before you start, confirm:
- A Linux host you control (examples below use Ubuntu/Debian
apt; RHEL/Fedora users should substitutednf install clamav clamav-update clamd) - At least 2GB free disk space — the signature database (
daily.cvd,main.cvd,bytecode.cvd) is roughly 500MB–1GB and grows over time - A non-production directory or VM to test scanning behavior before pointing it at live file shares
systemdfor managing theclamav-freshclamandclamav-daemonservices
Resource note:
clamdloads the entire signature database into memory per worker. Budget at least 1–2GB of RAM headroom on small VPS instances, or scanning will be killed by the OOM killer mid-run.
Step 1: Install ClamAV
sudo apt update
sudo apt install -y clamav clamav-daemon clamav-freshclamStop the daemon briefly so you can run an initial signature download without a lock conflict:
sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl start clamav-freshclam
sudo systemctl enable clamav-freshclamfreshclam pulls the latest main.cvd, daily.cvd, and bytecode.cvd definitions from ClamAV's CDN. On a fresh install this can take several minutes.
Step 2: Start the clamd daemon
clamscan (on-demand CLI) reloads the entire signature set into memory on every invocation — fine for occasional scans, painfully slow for frequent ones. clamd keeps signatures resident and accepts scan requests over a Unix socket, so repeated scans are near-instant.
sudo systemctl enable --now clamav-daemon
sudo systemctl status clamav-daemonConfirm the socket is listening:
sudo ls -la /var/run/clamav/clamd.ctlEdit /etc/clamav/clamd.conf to tune behavior for your workload. Key settings:
MaxDirectoryRecursion 20
MaxFileSize 100M
MaxScanSize 400M
StreamMaxLength 100M
LogFile /var/log/clamav/clamav.log
LogTime yesRestart after any config change:
sudo systemctl restart clamav-daemonStep 3: Scan via clamdscan (fast path)
Use clamdscan instead of clamscan for any repeated or scripted scanning — it talks to the already-running clamd process instead of reloading signatures each time.
sudo clamdscan --fdpass /srv/fileshare/incoming/--fdpass passes file descriptors directly to clamd, which avoids permission errors when clamd runs as a different user than the one invoking the scan (common on shared file servers).
For a one-off, no-daemon scan of a single path:
clamscan -r --bell -i /home/*/Downloads/-r recurses, -i prints only infected files, --bell rings the terminal bell on a hit — useful when watching a long scan interactively.
Step 4: Automate quarantine on detection
ClamAV doesn't quarantine by default — it only reports. Wire up a quarantine action with a wrapper script:
sudo mkdir -p /var/quarantine/clamav
sudo chmod 700 /var/quarantine/clamav#!/bin/bash
# /usr/local/bin/clamav-scan-quarantine.sh
SCAN_DIR="${1:?Usage: $0 <directory>}"
QUARANTINE_DIR="/var/quarantine/clamav"
LOG="/var/log/clamav/quarantine.log"
sudo clamdscan --fdpass --move="$QUARANTINE_DIR" --log="$LOG" "$SCAN_DIR"sudo chmod +x /usr/local/bin/clamav-scan-quarantine.sh--move relocates any infected file into $QUARANTINE_DIR the moment it's flagged, instead of leaving it in place for a user to open before anyone reviews the log.
Step 5: Schedule signature updates and recurring scans
clamav-freshclam already runs continuously as a service and checks for new signatures roughly every 2 hours by default — confirm the interval in /etc/clamav/freshclam.conf (Checks 24 means 24 checks/day):
Checks 24Schedule a nightly full scan with quarantine via cron:
sudo crontab -e0 2 * * * /usr/local/bin/clamav-scan-quarantine.sh /srv/fileshare >> /var/log/clamav/nightly-scan.log 2>&1For mail gateways, hook ClamAV into Postfix via amavisd-new or clamav-milter so every inbound message is scanned before delivery — that's a separate milter configuration, but the clamd daemon you just set up is the engine both paths call into.
Verification / Testing
Use the EICAR test string — a standardized, harmless string every AV engine recognizes as "infected" for testing purposes. Never test with real malware.
curl -s https://secure.eicar.org/eicar.com.txt -o /tmp/eicar-test.txt
sudo clamdscan /tmp/eicar-test.txtExpected output:
/tmp/eicar-test.txt: Win.Test.EICAR_HDB-1 FOUND
----------- SCAN SUMMARY -----------
Infected files: 1
Then confirm the quarantine wrapper actually moves it:
/usr/local/bin/clamav-scan-quarantine.sh /tmp/
ls -la /var/quarantine/clamav/You should see eicar-test.txt relocated out of /tmp and into the quarantine directory, with a corresponding entry in /var/log/clamav/quarantine.log.
Troubleshooting
- **
freshclamfails with "ERROR: Can't download daily.cvd"** — check outbound HTTPS todatabase.clamav.net; corporate proxies often block the CDN. SetHTTPProxyServerin/etc/clamav/freshclam.conf` if needed. clamdwon't start, log shows "ERROR: Can't allocate memory" — the signature database didn't fit in available RAM. Add swap or reduceMaxThreadsinclamd.conf.clamdscanreturns "Permission denied" on files clamd can read fine manually — use--fdpass, or add the invoking user to theclamavgroup and ensure directory permissions allow traversal (chmod o+xon parent dirs).- Scans are slow on large file shares — exclude known-safe large binaries (VM images, backups) via
ExcludePathinclamd.confrather than scanning everything on every pass. - False positive on a legitimate file — submit it to ClamAV's false positive form rather than just whitelisting blindly; also check if a
bytecode.cvdsignature was recently updated and is overly broad.
Summary
ClamAV won't replace a modern endpoint agent, but it closes a real gap: unscanned file shares, upload directories, and mail queues that endpoint AV never touches until it's too late. Running clamd as a persistent daemon instead of invoking clamscan repeatedly keeps scans fast enough for cron-driven automation, and a simple quarantine wrapper turns "detected" into "contained" without manual intervention. Point it at your riskiest ingestion points first — inbound mail, upload forms, shared drives — before trying to scan everything.