HOWTOIntermediate

Deploying ClamAV for Automated Antivirus Scanning on Linux Servers

Install and configure ClamAV to automatically scan file shares, mail queues, and uploaded files on Linux — with scheduled scans, quarantine, and real-time monitoring via clamd.

Dylan H.

Tutorials

October 19, 2026
6 min read
Deploying ClamAV for Automated Antivirus Scanning on Linux Servers

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 substitute dnf 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
  • systemd for managing the clamav-freshclam and clamav-daemon services

Resource note: clamd loads 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-freshclam

Stop 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-freshclam

freshclam 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-daemon

Confirm the socket is listening:

sudo ls -la /var/run/clamav/clamd.ctl

Edit /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 yes

Restart after any config change:

sudo systemctl restart clamav-daemon

Step 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 24

Schedule a nightly full scan with quarantine via cron:

sudo crontab -e
0 2 * * * /usr/local/bin/clamav-scan-quarantine.sh /srv/fileshare >> /var/log/clamav/nightly-scan.log 2>&1

For 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.txt

Expected 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

  • **freshclam fails with "ERROR: Can't download daily.cvd"** — check outbound HTTPS to database.clamav.net; corporate proxies often block the CDN. Set HTTPProxyServerin/etc/clamav/freshclam.conf` if needed.
  • clamd won't start, log shows "ERROR: Can't allocate memory" — the signature database didn't fit in available RAM. Add swap or reduce MaxThreads in clamd.conf.
  • clamdscan returns "Permission denied" on files clamd can read fine manually — use --fdpass, or add the invoking user to the clamav group and ensure directory permissions allow traversal (chmod o+x on parent dirs).
  • Scans are slow on large file shares — exclude known-safe large binaries (VM images, backups) via ExcludePath in clamd.conf rather 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.cvd signature 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.