Build a comprehensive security monitoring infrastructure with ClamAV antivirus scanning, Elasticsearch log storage, and automated threat detection. This setup provides real-time malware scanning with centralized log aggregation for enterprise security compliance.
Prerequisites
- Root or sudo access
- Minimum 4GB RAM
- 20GB free disk space
- Network connectivity for virus definition updates
- SMTP server for email alerts
What this solves
This tutorial creates a centralized security monitoring platform that combines ClamAV's real-time antivirus scanning with Elasticsearch's powerful log aggregation and analysis capabilities. You'll build an infrastructure that automatically scans files for malware, processes security logs from multiple sources, and generates alerts for suspicious activities across your network.
Step-by-step installation
Update system packages and install Java
Start by updating your system and installing Java 11 or higher, which is required for Elasticsearch.
sudo apt update && sudo apt upgrade -y
sudo apt install -y openjdk-17-jdk curl gnupg2 software-properties-common
Install Elasticsearch 8
Add the Elasticsearch repository and install the latest version with security features enabled by default.
curl -fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
sudo apt update
sudo apt install -y elasticsearch
Configure Elasticsearch for security monitoring
Configure Elasticsearch with optimized settings for security log processing and adequate memory allocation.
cluster.name: security-monitoring
node.name: security-node-1
network.host: 0.0.0.0
http.port: 9200
discovery.type: single-node
xpack.security.enabled: true
xpack.security.enrollment.enabled: true
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: certs/http.p12
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: certs/transport.p12
xpack.security.transport.ssl.truststore.path: certs/transport.p12
bootstrap.memory_lock: true
indices.query.bool.max_clause_count: 10000
Configure Elasticsearch JVM heap size
Set the JVM heap to half of your available RAM for optimal performance. This example uses 2GB for a 4GB system.
-Xms2g
-Xmx2g
Start and configure Elasticsearch
Start Elasticsearch and save the auto-generated elastic user password for later use.
sudo systemctl daemon-reload
sudo systemctl enable --now elasticsearch
sudo systemctl status elasticsearch
Reset the elastic user password and save it securely:
sudo /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic -i
Install ClamAV antivirus scanner
Install ClamAV daemon and utilities for real-time virus scanning capabilities.
sudo apt install -y clamav clamav-daemon clamav-freshclam clamav-unofficial-sigs
Configure ClamAV daemon
Configure ClamAV daemon for optimal scanning performance and logging integration with Elasticsearch.
LogFile /var/log/clamav/clamav.log
LogTime yes
LogClean yes
LogSyslog yes
LogFacility LOG_LOCAL6
LogVerbose yes
ExtendedDetectionInfo yes
PidFile /var/run/clamav/clamd.pid
LocalSocket /var/run/clamav/clamd.ctl
FixStaleSocket yes
LocalSocketGroup clamav
LocalSocketMode 666
User clamav
ScanMail yes
ScanArchive yes
ArchiveBlockEncrypted no
MaxDirectoryRecursion 15
FollowDirectorySymlinks no
FollowFileSymlinks no
ReadTimeout 180
MaxThreads 12
MaxConnectionQueueLength 15
StreamMaxLength 25M
MaxFiles 10000
MaxRecursion 16
MaxFileSize 25M
ScanPDF yes
ScanSWF yes
ScanXMLDOCS yes
ScanHWP3 yes
ScanOLE2 yes
AlertBrokenExecutables yes
AlertBrokenMedia no
AlertEncrypted no
AlertEncryptedArchive no
AlertEncryptedDoc no
AlertOLE2Macros yes
AlertPhishingSSLMismatch yes
AlertPhishingCloak yes
AlertPartitionIntersection no
HeuristicScanPrecedence no
StructuredDataDetection no
CommandReadTimeout 30
SendBufTimeout 200
MaxQueue 100
IdleTimeout 30
ExcludePath ^/proc/
ExcludePath ^/sys/
Configure ClamAV freshclam for updates
Set up automatic virus definition updates to ensure protection against the latest threats.
DatabaseDirectory /var/lib/clamav
UpdateLogFile /var/log/clamav/freshclam.log
LogVerbose yes
LogSyslog yes
LogFacility LOG_LOCAL6
LogFileMaxSize 0
LogRotate yes
LogTime yes
Foreground no
Debug no
MaxAttempts 5
DatabaseOwner clamav
AllowSupplementaryGroups yes
NotifyClamd /etc/clamav/clamd.conf
Checks 24
ConnectTimeout 30
ReceiveTimeout 0
TestDatabases yes
ScriptedUpdates yes
CompressLocalDatabase no
Bytecode yes
IncludePUA Packed
IncludePUA PWS
IncludePUA Casino
IncludePUA Suspect
ExtraDatabase /var/lib/clamav-unofficial-sigs
Install and configure Logstash
Install Logstash to process and forward ClamAV logs to Elasticsearch for analysis.
sudo apt install -y logstash
Create Logstash pipeline configuration
Configure Logstash to parse ClamAV logs and send structured data to Elasticsearch with proper field mapping.
input {
file {
path => "/var/log/clamav/clamav.log"
start_position => "beginning"
sincedb_path => "/var/lib/logstash/sincedb_clamav"
tags => ["clamav"]
}
syslog {
port => 5514
tags => ["security-logs"]
}
}
filter {
if "clamav" in [tags] {
grok {
match => {
"message" => "%{TIMESTAMP_ISO8601:timestamp} -> %{GREEDYDATA:clamav_message}"
}
}
if [clamav_message] =~ /FOUND/ {
mutate {
add_field => { "threat_detected" => "true" }
add_field => { "severity" => "high" }
}
grok {
match => {
"clamav_message" => "%{PATH:infected_file}: %{DATA:virus_name} FOUND"
}
}
}
if [clamav_message] =~ /OK$/ {
mutate {
add_field => { "threat_detected" => "false" }
add_field => { "severity" => "low" }
}
}
date {
match => [ "timestamp", "ISO8601" ]
}
}
mutate {
add_field => { "[@metadata][index]" => "security-monitoring-%{+YYYY.MM.dd}" }
}
}
output {
elasticsearch {
hosts => ["https://localhost:9200"]
index => "%{[@metadata][index]}"
user => "elastic"
password => "${ELASTIC_PASSWORD}"
ssl_certificate_verification => false
ssl_enabled => true
}
if [threat_detected] == "true" {
email {
to => "security@example.com"
subject => "Security Alert: Malware Detected - %{virus_name}"
body => "Threat detected on %{host}: %{infected_file} contains %{virus_name}\n\nTimestamp: %{@timestamp}\nSeverity: %{severity}"
from => "security-system@example.com"
smtp_host => "localhost"
smtp_port => 25
}
}
}
Set up environment variables for Logstash
Create environment file with Elasticsearch credentials for secure authentication.
ELASTIC_PASSWORD=your-elastic-password-here
sudo chown root:logstash /etc/logstash/startup.options
sudo chmod 640 /etc/logstash/startup.options
Configure rsyslog for centralized logging
Set up rsyslog to forward ClamAV syslog messages to Logstash for centralized processing.
# ClamAV logging configuration
local6.* @@127.0.0.1:5514
Stop processing after sending to Logstash
& stop
sudo systemctl restart rsyslog
Create ClamAV scanning scripts
Create automated scanning scripts for different directories and file types with proper logging integration.
#!/bin/bash
Automated home directory scanning script
LOGFILE="/var/log/clamav/scheduled-scan.log"
SCAN_DIR="/home"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] Starting scheduled scan of $SCAN_DIR" >> $LOGFILE
/usr/bin/clamscan -r -i --bell --log=$LOGFILE $SCAN_DIR
SCAN_EXIT_CODE=$?
if [ $SCAN_EXIT_CODE -eq 0 ]; then
echo "[$DATE] Scan completed successfully - No threats found" >> $LOGFILE
logger -p local6.info "ClamAV: Scheduled scan of $SCAN_DIR completed successfully"
elif [ $SCAN_EXIT_CODE -eq 1 ]; then
echo "[$DATE] THREAT DETECTED during scan of $SCAN_DIR" >> $LOGFILE
logger -p local6.warn "ClamAV: THREAT DETECTED during scheduled scan of $SCAN_DIR"
# Send immediate notification
mail -s "URGENT: Malware detected on $(hostname)" security@example.com < $LOGFILE
else
echo "[$DATE] Scan error occurred (exit code: $SCAN_EXIT_CODE)" >> $LOGFILE
logger -p local6.error "ClamAV: Scan error occurred for $SCAN_DIR (exit code: $SCAN_EXIT_CODE)"
fi
sudo chmod +x /usr/local/bin/clamav-scan-home.sh
sudo chown clamav:clamav /usr/local/bin/clamav-scan-home.sh
Set up automated scanning schedule
Configure systemd timers for regular automated scanning with different intervals for various directories.
[Unit]
Description=ClamAV Home Directory Scan
After=network.target
[Service]
Type=oneshot
User=clamav
ExecStart=/usr/local/bin/clamav-scan-home.sh
StandardOutput=journal
StandardError=journal
[Unit]
Description=Run ClamAV home scan daily at 2 AM
Requires=clamav-home-scan.service
[Timer]
OnCalendar=daily
Persistent=true
AccuracySec=1h
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now clamav-home-scan.timer
sudo systemctl list-timers clamav-home-scan.timer
Start and enable all services
Start all components of the security monitoring stack and ensure they start automatically on boot.
# Update ClamAV virus definitions
sudo freshclam
Start ClamAV services
sudo systemctl enable --now clamav-freshclam
sudo systemctl enable --now clamav-daemon
Start Logstash with environment variables
sudo systemctl enable --now logstash
Verify all services are running
sudo systemctl status elasticsearch clamav-daemon clamav-freshclam logstash
Create Elasticsearch index template
Set up a proper index template for security monitoring data with optimized field mappings and retention policies.
curl -X PUT "https://localhost:9200/_index_template/security-monitoring" \
-H "Content-Type: application/json" \
-u elastic:your-elastic-password \
-k -d '{
"index_patterns": ["security-monitoring-*"],
"template": {
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0,
"index.lifecycle.name": "security-monitoring-policy",
"index.lifecycle.rollover_alias": "security-monitoring"
},
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"host": { "type": "keyword" },
"threat_detected": { "type": "boolean" },
"severity": { "type": "keyword" },
"virus_name": { "type": "keyword" },
"infected_file": { "type": "text", "fields": { "keyword": { "type": "keyword" } } },
"clamav_message": { "type": "text" },
"message": { "type": "text" }
}
}
}
}'
Verify your setup
Test the complete security monitoring pipeline with these verification steps:
# Check Elasticsearch cluster health
curl -X GET "https://localhost:9200/_cluster/health" -u elastic:your-elastic-password -k
Verify ClamAV is scanning properly
sudo systemctl status clamav-daemon
echo "X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*" > /tmp/eicar.txt
clamscan /tmp/eicar.txt
rm /tmp/eicar.txt
Check Logstash pipeline status
sudo systemctl status logstash
curl -X GET "https://localhost:9200/security-monitoring-*/_search?pretty" -u elastic:your-elastic-password -k
Test automated scanning
sudo /usr/local/bin/clamav-scan-home.sh
Verify log forwarding
tail -f /var/log/clamav/clamav.log
journalctl -u logstash -f
Configure alerting and monitoring dashboards
Install Kibana for visualization
Install Kibana to create security dashboards and configure alerting rules for threat detection.
sudo apt install -y kibana
Configure Kibana for security monitoring
Set up Kibana with proper authentication and SSL configuration to access your security monitoring data.
server.port: 5601
server.host: "0.0.0.0"
server.name: "security-monitoring-kibana"
elasticsearch.hosts: ["https://localhost:9200"]
elasticsearch.username: "elastic"
elasticsearch.password: "your-elastic-password"
elasticsearch.ssl.verificationMode: none
xpack.security.enabled: true
xpack.security.session.idleTimeout: "1h"
xpack.security.session.lifespan: "30d"
logging.appenders.file.fileName: /var/log/kibana/kibana.log
logging.root.level: info
sudo systemctl enable --now kibana
sudo systemctl status kibana
Create security monitoring dashboard
Access Kibana at http://your-server-ip:5601 and create index patterns and dashboards for security monitoring.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Elasticsearch won't start | Insufficient memory or wrong Java version | Check sudo journalctl -u elasticsearch and adjust heap size in jvm.options |
| ClamAV database updates fail | Network connectivity or proxy issues | Check /var/log/clamav/freshclam.log and configure proxy if needed |
| Logstash pipeline not processing logs | File permissions or Elasticsearch authentication | Verify logstash user can read log files: sudo usermod -a -G clamav logstash |
| No data appearing in Kibana | Index pattern mismatch or time range issues | Check index pattern matches 'security-monitoring-*' and adjust time range |
| High memory usage by Elasticsearch | Default heap size too large for system | Adjust Xms and Xmx values in /etc/elasticsearch/jvm.options.d/heap.options |
| Email alerts not working | SMTP configuration or missing mail server | Install postfix: sudo apt install postfix and configure relay |
Next steps
- Integrate ClamAV with web servers and email systems for comprehensive scanning
- Expand your ELK stack setup for additional log sources and retention policies
- Set up advanced alerting with Grafana for security metrics visualization
- Add DDoS protection and rate limiting to complement your security monitoring
- Configure centralized logging for additional system security events
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Print functions
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
print_info() { echo -e "${YELLOW}[INFO]${NC} $1"; }
# Usage
usage() {
echo "Usage: $0 [--heap-size SIZE]"
echo "Options:"
echo " --heap-size SIZE Elasticsearch heap size (default: 2g)"
echo "Example: $0 --heap-size 4g"
exit 1
}
# Parse arguments
HEAP_SIZE="2g"
while [[ $# -gt 0 ]]; do
case $1 in
--heap-size) HEAP_SIZE="$2"; shift 2 ;;
-h|--help) usage ;;
*) print_error "Unknown option: $1"; usage ;;
esac
done
# Cleanup on failure
cleanup() {
print_error "Installation failed. Cleaning up..."
systemctl stop elasticsearch clamav-daemon freshclam 2>/dev/null || true
systemctl disable elasticsearch clamav-daemon freshclam 2>/dev/null || true
}
trap cleanup ERR
# Check prerequisites
if [[ $EUID -ne 0 ]]; then
print_error "This script must be run as root"
exit 1
fi
# Detect distribution
if [ ! -f /etc/os-release ]; then
print_error "/etc/os-release not found. Cannot detect distribution."
exit 1
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_INSTALL="apt install -y"
PKG_UPGRADE="apt upgrade -y"
CLAMAV_DAEMON="clamav-daemon"
CLAMAV_FRESHCLAM="clamav-freshclam"
CLAMD_CONF="/etc/clamav/clamd.conf"
FRESHCLAM_CONF="/etc/clamav/freshclam.conf"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf makecache"
PKG_INSTALL="dnf install -y"
PKG_UPGRADE="dnf update -y"
CLAMAV_DAEMON="clamd@scan"
CLAMAV_FRESHCLAM="clamav-freshclam"
CLAMD_CONF="/etc/clamd.d/scan.conf"
FRESHCLAM_CONF="/etc/freshclam.conf"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum makecache"
PKG_INSTALL="yum install -y"
PKG_UPGRADE="yum update -y"
CLAMAV_DAEMON="clamd@amavisd"
CLAMAV_FRESHCLAM="clamav-freshclam"
CLAMD_CONF="/etc/clamd.d/amavisd.conf"
FRESHCLAM_CONF="/etc/freshclam.conf"
;;
*)
print_error "Unsupported distribution: $ID"
exit 1
;;
esac
print_info "Detected distribution: $PRETTY_NAME"
print_info "Using package manager: $PKG_MGR"
# Step 1: Update system and install Java
echo "[1/7] Updating system and installing Java..."
$PKG_UPDATE
$PKG_UPGRADE
if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then
$PKG_INSTALL openjdk-17-jdk curl gnupg2 software-properties-common
else
$PKG_INSTALL java-17-openjdk curl gnupg2
fi
# Step 2: Install Elasticsearch
echo "[2/7] Installing Elasticsearch..."
if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then
curl -fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch | gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" > /etc/apt/sources.list.d/elastic-8.x.list
apt update
$PKG_INSTALL elasticsearch
else
rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
cat > /etc/yum.repos.d/elasticsearch.repo << 'EOF'
[elasticsearch]
name=Elasticsearch repository for 8.x packages
baseurl=https://artifacts.elastic.co/packages/8.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=0
autorefresh=1
type=rpm-md
EOF
$PKG_INSTALL --enablerepo=elasticsearch elasticsearch
fi
# Step 3: Configure Elasticsearch
echo "[3/7] Configuring Elasticsearch..."
cat > /etc/elasticsearch/elasticsearch.yml << 'EOF'
cluster.name: security-monitoring
node.name: security-node-1
network.host: 0.0.0.0
http.port: 9200
discovery.type: single-node
xpack.security.enabled: true
xpack.security.enrollment.enabled: true
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: certs/http.p12
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: certs/transport.p12
xpack.security.transport.ssl.truststore.path: certs/transport.p12
bootstrap.memory_lock: true
indices.query.bool.max_clause_count: 10000
EOF
chown root:elasticsearch /etc/elasticsearch/elasticsearch.yml
chmod 644 /etc/elasticsearch/elasticsearch.yml
# Configure JVM heap
cat > /etc/elasticsearch/jvm.options.d/heap.options << EOF
-Xms${HEAP_SIZE}
-Xmx${HEAP_SIZE}
EOF
# Step 4: Start Elasticsearch
echo "[4/7] Starting Elasticsearch..."
systemctl daemon-reload
systemctl enable elasticsearch
systemctl start elasticsearch
# Wait for Elasticsearch to start
sleep 30
# Step 5: Install ClamAV
echo "[5/7] Installing ClamAV..."
if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then
$PKG_INSTALL clamav clamav-daemon clamav-freshclam
else
$PKG_INSTALL epel-release
$PKG_INSTALL clamav clamav-scanner clamav-scanner-systemd clamav-update
fi
# Step 6: Configure ClamAV
echo "[6/7] Configuring ClamAV..."
mkdir -p /var/log/clamav
chown clamav:clamav /var/log/clamav
chmod 755 /var/log/clamav
# Stop services for configuration
systemctl stop $CLAMAV_DAEMON $CLAMAV_FRESHCLAM 2>/dev/null || true
# Configure clamd
if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then
sed -i 's/^Example/#Example/' $CLAMD_CONF
fi
cat >> $CLAMD_CONF << 'EOF'
LogFile /var/log/clamav/clamav.log
LogTime yes
LogClean yes
LogSyslog yes
LogFacility LOG_LOCAL6
LogVerbose yes
ExtendedDetectionInfo yes
ScanMail yes
ScanArchive yes
ArchiveBlockEncrypted no
MaxDirectoryRecursion 15
FollowDirectorySymlinks no
FollowFileSymlinks no
ReadTimeout 180
MaxThreads 12
MaxConnectionQueueLength 15
StreamMaxLength 100M
EOF
# Configure freshclam
if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then
sed -i 's/^Example/#Example/' $FRESHCLAM_CONF
fi
cat >> $FRESHCLAM_CONF << 'EOF'
UpdateLogFile /var/log/clamav/freshclam.log
LogSyslog yes
LogTime yes
DatabaseDirectory /var/lib/clamav
DatabaseOwner clamav
DatabaseMirror db.local.clamav.net
DatabaseMirror database.clamav.net
MaxAttempts 3
CompressLocalDatabase no
EOF
chown clamav:clamav $CLAMD_CONF $FRESHCLAM_CONF
chmod 644 $CLAMD_CONF $FRESHCLAM_CONF
# Update virus definitions
print_info "Updating virus definitions..."
freshclam
# Step 7: Start services and verify
echo "[7/7] Starting services and verifying installation..."
systemctl enable $CLAMAV_DAEMON $CLAMAV_FRESHCLAM
systemctl start $CLAMAV_DAEMON $CLAMAV_FRESHCLAM
# Verify services
sleep 10
ES_STATUS=$(systemctl is-active elasticsearch || echo "failed")
CLAMD_STATUS=$(systemctl is-active $CLAMAV_DAEMON || echo "failed")
FRESH_STATUS=$(systemctl is-active $CLAMAV_FRESHCLAM || echo "failed")
echo
print_info "=== Installation Summary ==="
if [[ "$ES_STATUS" == "active" ]]; then
print_success "Elasticsearch: Running"
else
print_error "Elasticsearch: Failed to start"
fi
if [[ "$CLAMD_STATUS" == "active" ]]; then
print_success "ClamAV Daemon: Running"
else
print_error "ClamAV Daemon: Failed to start"
fi
if [[ "$FRESH_STATUS" == "active" ]]; then
print_success "Freshclam: Running"
else
print_error "Freshclam: Failed to start"
fi
print_info "Next steps:"
print_info "1. Reset Elasticsearch password: /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic -i"
print_info "2. Elasticsearch is available at: https://localhost:9200"
print_info "3. ClamAV logs: /var/log/clamav/"
print_info "4. Configure firewall rules as needed"
Review the script before running. Execute with: bash install.sh