Configure ClamAV integration with web servers and email systems for automated threat detection

Intermediate 45 min Apr 29, 2026 515 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Integrate ClamAV antivirus with NGINX, Apache, Postfix and Dovecot for automated file scanning and email protection. Set up real-time threat detection with monitoring and alerting.

Prerequisites

  • Root or sudo access
  • Web server (NGINX or Apache) installed
  • Mail server (Postfix/Dovecot) installed
  • At least 2GB RAM for ClamAV database
  • Mail utility for alerting

What this solves

ClamAV provides open-source antivirus scanning that integrates with web servers and email systems to automatically scan uploaded files and email attachments. This tutorial shows you how to configure ClamAV with NGINX, Apache, Postfix, and Dovecot to create a comprehensive threat detection system that protects your infrastructure from malware and viruses in real-time.

Step-by-step installation

Install ClamAV daemon and tools

Install the ClamAV antivirus engine and daemon that will handle scanning requests from web servers and email systems.

sudo apt update
sudo apt install -y clamav clamav-daemon clamav-freshclam clamav-milter
sudo systemctl stop clamav-freshclam
sudo dnf update -y
sudo dnf install -y clamav clamav-devel clamav-update clamav-milter
sudo systemctl stop clamav-freshclam

Update virus definitions

Download the latest virus signature database before starting the daemon. This ensures immediate threat detection capability.

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

Configure ClamAV daemon

Set up the ClamAV daemon with network socket support for web server and email integration. Configure memory limits and scanning options.

LogFile /var/log/clamav/clamav.log
LogTime yes
LogFileUnlock yes
LogFileMaxSize 100M
LogRotate yes
LogVerbose yes
PidFile /var/run/clamav/clamd.pid
TemporaryDirectory /tmp
DatabaseDirectory /var/lib/clamav
LocalSocket /var/run/clamav/clamd.ctl
TCPSocket 3310
TCPAddr 127.0.0.1
MaxConnectionQueueLength 15
MaxThreads 20
ReadTimeout 300
CommandReadTimeout 30
SendBufTimeout 200
MaxQueue 100
IdleTimeout 30
ExcludePath ^/proc/
ExcludePath ^/sys/
AlertBrokenExecutables yes
AlertPhishingSSLMismatch yes
AlertPhishingCloak yes
AlertPartitionIntersection yes
ScanPE yes
ScanELF yes
ScanOLE2 yes
ScanPDF yes
ScanHTML yes
ScanMail yes
ScanArchive yes
ArchiveBlockEncrypted no
MaxScanSize 500M
MaxFileSize 100M
MaxRecursion 16
MaxFiles 10000
MaxEmbeddedPE 10M
MaxHTMLNormalize 10M
MaxHTMLNoTags 2M
MaxScriptNormalize 5M
MaxZipTypeRcg 1M
User clamav
Bytecode yes
BytecodeSecurity TrustSigned
BytecodeTimeout 60000
DetectPUA yes

Create ClamAV user and directories

Set up proper ownership and permissions for ClamAV directories and socket files.

sudo mkdir -p /var/run/clamav /var/log/clamav
sudo chown -R clamav:clamav /var/run/clamav /var/log/clamav
sudo chmod 755 /var/run/clamav /var/log/clamav

Start ClamAV daemon

Enable and start the ClamAV daemon service for immediate threat scanning capability.

sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
sudo systemctl status clamav-daemon

Configure NGINX integration

Install NGINX ClamAV module

Install the NGINX module that enables real-time file scanning for uploaded files through ClamAV integration.

sudo apt install -y nginx-extras
sudo apt install -y libnginx-mod-http-upstream-fair
sudo dnf install -y nginx nginx-mod-http-perl
sudo dnf install -y lua-devel pcre-devel

Configure NGINX upstream for ClamAV

Create an upstream configuration that routes file uploads through ClamAV scanning before processing.

upstream clamav_backend {
    server 127.0.0.1:3310 max_fails=3 fail_timeout=30s;
    keepalive 32;
}

map $request_method $upload_method {
    POST "scan";
    PUT "scan";
    default "pass";
}

Create ClamAV scanning location

Configure NGINX location blocks that intercept file uploads and scan them through ClamAV before allowing access.

server {
    listen 80;
    server_name example.com;
    
    client_max_body_size 100M;
    client_body_temp_path /tmp/nginx_uploads;
    
    location /upload {
        if ($upload_method = "scan") {
            access_by_lua_block {
                local socket = require "resty.socket"
                local tcp = socket.tcp()
                local ok, err = tcp:connect("127.0.0.1", 3310)
                
                if not ok then
                    ngx.log(ngx.ERR, "Failed to connect to ClamAV: ", err)
                    ngx.status = 503
                    ngx.say("Antivirus scanning unavailable")
                    ngx.exit(503)
                end
                
                local bytes, err = tcp:send("PING\n")
                if not bytes then
                    ngx.log(ngx.ERR, "Failed to ping ClamAV")
                    ngx.status = 503
                    ngx.exit(503)
                end
                
                tcp:close()
            }
        }
        
        proxy_pass http://backend_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    location /health/clamav {
        access_log off;
        return 200 "ClamAV integration active\n";
        add_header Content-Type text/plain;
    }
}

Create upload scanning script

Create a script that scans uploaded files and returns appropriate HTTP status codes based on scan results.

#!/bin/bash

FILE_PATH="$1"
SOCKET="/var/run/clamav/clamd.ctl"

if [[ ! -f "$FILE_PATH" ]]; then
    echo "ERROR: File not found"
    exit 1
fi

# Scan file with ClamAV
RESULT=$(clamdscan --fdpass "$FILE_PATH" 2>/dev/null)
EXIT_CODE=$?

if [[ $EXIT_CODE -eq 0 ]]; then
    echo "CLEAN: File passed antivirus scan"
    exit 0
elif [[ $EXIT_CODE -eq 1 ]]; then
    echo "INFECTED: $RESULT"
    # Log threat detection
    logger -t "nginx-clamav" "THREAT DETECTED: $FILE_PATH - $RESULT"
    # Remove infected file
    rm -f "$FILE_PATH"
    exit 1
else
    echo "ERROR: Scan failed"
    exit 2
fi
sudo chmod +x /usr/local/bin/nginx-clamav-scan
sudo chown root:root /usr/local/bin/nginx-clamav-scan

Configure Apache integration

Install Apache ClamAV module

Install the mod_clamav module for Apache that provides real-time antivirus scanning capabilities.

sudo apt install -y libapache2-mod-clamav
sudo a2enmod clamav
sudo systemctl reload apache2
sudo dnf install -y mod_clamav
echo "LoadModule clamav_module modules/mod_clamav.so" >> /etc/httpd/conf.modules.d/10-clamav.conf
sudo systemctl reload httpd

Configure Apache ClamAV scanning

Set up Apache virtual host configuration with ClamAV integration for automatic file upload scanning.

Create quarantine directory

Set up a secure quarantine directory for infected files detected by Apache ClamAV integration.

sudo mkdir -p /var/quarantine
sudo chown www-data:www-data /var/quarantine
sudo chmod 750 /var/quarantine

Enable Apache site and reload

Activate the ClamAV-enabled Apache site configuration and reload the web server.

sudo a2ensite clamav-scan.conf
sudo systemctl reload apache2
sudo cp /etc/apache2/sites-available/clamav-scan.conf /etc/httpd/conf.d/
sudo systemctl reload httpd

Configure Postfix email integration

Install Amavisd-new for email scanning

Install Amavisd-new which integrates ClamAV with Postfix for comprehensive email scanning and threat detection.

sudo apt install -y amavisd-new spamassassin
sudo adduser clamav amavis
sudo adduser amavis clamav
sudo dnf install -y amavisd-new spamassassin
sudo usermod -a -G amavis clamav
sudo usermod -a -G clamav amavis

Configure Amavisd-new

Set up Amavisd-new configuration to route email through ClamAV scanning with proper virus handling policies.

# Enable virus scanning
@bypass_virus_checks_maps = (
   %bypass_virus_checks, @bypass_virus_checks_acl, $bypass_virus_checks_re);

# Enable spam scanning
@bypass_spam_checks_maps = (
   %bypass_spam_checks, @bypass_spam_checks_acl, $bypass_spam_checks_re);

1;  # ensure a defined return

Configure Amavisd-new main settings

Configure the main Amavisd-new settings for ClamAV integration with appropriate logging and quarantine policies.

use strict;

# Daemon user and group
$daemon_user  = "amavis";
$daemon_group = "amavis";

# Directories
$MYHOME = '/var/lib/amavis';
$TEMPBASE = "$MYHOME/tmp";
$ENV{TMPDIR} = $TEMPBASE;
$QUARANTINEDIR = '/var/lib/amavis/virusmails';

# Logging
$log_level = 2;
$enable_db = 1;
$enable_global_cache = 1;

# ClamAV settings
@av_scanners = (
    ['ClamAV-clamd',
     \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.ctl"],
     qr/\bOK$/m, qr/\bFOUND$/m,
     qr/^.*?: (?![\d\s]+$)(.*) FOUND$/m ],
);

# Virus handling
$final_virus_destiny = D_DISCARD;
$final_spam_destiny = D_REJECT;

# Network settings
$inet_socket_port = 10024;
$inet_socket_bind = '127.0.0.1';
$policy_bank{'ORIGINATING'} = {
    originating => 1,
    allow_disclaimers => 1,
};

# Interface policy
$interface_policy{'10025'} = 'ORIGINATING';

1;

Configure Postfix master.cf

Modify Postfix master.cf to route email through Amavisd-new for ClamAV scanning before delivery.

# Add these lines to master.cf
amavis      unix    -       -       -       -       2       smtp
    -o smtp_data_done_timeout=1200
    -o smtp_send_xforward_command=yes
    -o disable_dns_lookups=yes
    -o max_use=20

127.0.0.1:10025 inet    n       -       -       -       -       smtpd
    -o content_filter=
    -o local_recipient_maps=
    -o relay_recipient_maps=
    -o smtpd_restriction_classes=
    -o smtpd_delay_reject=no
    -o smtpd_client_restrictions=permit_mynetworks,reject
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o smtpd_data_restrictions=reject_unauth_pipelining
    -o smtpd_end_of_data_restrictions=
    -o mynetworks=127.0.0.0/8
    -o smtpd_error_sleep_time=0
    -o smtpd_soft_error_limit=1001
    -o smtpd_hard_error_limit=1000
    -o smtpd_client_connection_count_limit=0
    -o smtpd_client_connection_rate_limit=0
    -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks

Configure Postfix main.cf

Update Postfix main configuration to enable content filtering through Amavisd-new and ClamAV.

# Add or modify these lines in main.cf
content_filter = amavis:[127.0.0.1]:10024

# Amavis settings
amavis_destination_recipient_limit = 1
amavis_destination_concurrency_limit = 2

Configure Dovecot integration

Install Dovecot ClamAV plugin

Install the Dovecot antivirus plugin that integrates with ClamAV for real-time email scanning during IMAP/POP3 access.

sudo apt install -y dovecot-antispam dovecot-sieve
sudo dnf install -y dovecot dovecot-pigeonhole

Configure Dovecot antivirus plugin

Set up Dovecot configuration to scan emails through ClamAV when users access their mailboxes via IMAP or POP3.

plugin {
    # Antivirus scanning
    antivirus_backend = clamav
    antivirus_allow_empty = yes
    antivirus_max_size = 100M
    antivirus_send_email = yes
    antivirus_quarantine = /var/quarantine/dovecot/
    
    # ClamAV specific settings
    clamav_socket = /var/run/clamav/clamd.ctl
    clamav_action = reject
    clamav_timeout = 60
    
    # Logging
    antivirus_debug = no
    antivirus_verbose = yes
}

# Enable for IMAP
protocol imap {
    mail_plugins = $mail_plugins antivirus
}

# Enable for POP3
protocol pop3 {
    mail_plugins = $mail_plugins antivirus
}

Create Dovecot quarantine directory

Set up a quarantine directory for Dovecot with appropriate permissions for virus isolation.

sudo mkdir -p /var/quarantine/dovecot
sudo chown dovecot:dovecot /var/quarantine/dovecot
sudo chmod 750 /var/quarantine/dovecot

Configure Dovecot Sieve for virus filtering

Set up Sieve rules that automatically handle virus-infected emails detected by ClamAV integration.

require ["fileinto", "reject", "envelope", "regex"];

# Reject emails with viruses
if header :contains "X-Virus-Status" "infected" {
    reject "Message rejected: virus detected";
    stop;
}

# Quarantine suspicious emails
if header :contains "X-Spam-Level" "*****" {
    fileinto "Junk";
    stop;
}
sudo mkdir -p /var/mail/sieve
sudo chown -R dovecot:dovecot /var/mail/sieve
sudo sievec /var/mail/sieve/global.sieve

Set up monitoring and alerting

Create ClamAV monitoring script

Set up monitoring to track ClamAV daemon health, database updates, and scanning statistics with automated alerting.

#!/bin/bash

LOGFILE="/var/log/clamav-monitor.log"
STATUS_FILE="/var/run/clamav/monitor.status"
ALERT_EMAIL="admin@example.com"

log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOGFILE"
}

# Check ClamAV daemon status
check_daemon() {
    if ! systemctl is-active --quiet clamav-daemon; then
        log_message "ERROR: ClamAV daemon is not running"
        echo "DAEMON_DOWN" > "$STATUS_FILE"
        echo "ClamAV daemon is down on $(hostname)" | mail -s "ClamAV Alert" "$ALERT_EMAIL"
        return 1
    fi
    return 0
}

# Check database age
check_database() {
    DB_FILE="/var/lib/clamav/main.cvd"
    if [[ -f "$DB_FILE" ]]; then
        DB_AGE=$(find "$DB_FILE" -mtime +1 | wc -l)
        if [[ $DB_AGE -gt 0 ]]; then
            log_message "WARNING: Virus database is older than 24 hours"
            echo "DB_OLD" >> "$STATUS_FILE"
        fi
    else
        log_message "ERROR: Virus database not found"
        echo "DB_MISSING" > "$STATUS_FILE"
        return 1
    fi
    return 0
}

# Check socket connectivity
check_socket() {
    if ! clamdscan --ping &>/dev/null; then
        log_message "ERROR: Cannot connect to ClamAV socket"
        echo "SOCKET_ERROR" >> "$STATUS_FILE"
        return 1
    fi
    return 0
}

# Main monitoring
echo "CHECKING" > "$STATUS_FILE"

if check_daemon && check_database && check_socket; then
    log_message "INFO: All ClamAV checks passed"
    echo "HEALTHY" > "$STATUS_FILE"
else
    log_message "ERROR: ClamAV health check failed"
    echo "UNHEALTHY" > "$STATUS_FILE"
fi
sudo chmod +x /usr/local/bin/clamav-monitor
sudo chown root:root /usr/local/bin/clamav-monitor

Set up automated scanning reports

Create a script that generates daily reports of scanning activity and threat detections across all integrated services.

#!/bin/bash

REPORT_DATE=$(date '+%Y-%m-%d')
REPORT_FILE="/tmp/clamav

Automated install script

Run this to automate the entire setup

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. Fully managed, with one fixed contact who knows your setup.

You get one fixed contact who knows your setup

Rotterdam 01:28 · reachable in a message, no ticket form