Installing Linux Malware Detect (LMD) with ClamAV for Malware Scanning and Quarantine on Web Servers

Security tutorial - IT technology blog
Security tutorial - IT technology blog

2 AM. Telegram pings. A client messages: “Google just flagged my website as dangerous.” I SSH into the server and run ls -la /var/www/html — a bunch of suspicious .php files had appeared overnight. Webshells. Someone had uploaded them and was using the server as a botnet node.

After that incident, I set up LMD + ClamAV on all my web servers. Here’s the full walkthrough — from a 5-minute quick install to a complete automated setup.

Quick Start — Up and Running in 5 Minutes

If your server is suspected of being compromised and you need to scan immediately, follow these steps in order:

# 1. Install ClamAV first (large database, takes time to download)
sudo apt update && sudo apt install -y clamav clamav-daemon

# 2. Update virus database (important!)
sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl start clamav-freshclam

# 3. Download and install LMD
cd /tmp
wget https://www.rfxn.com/downloads/maldetect-current.tar.gz
tar -zxvf maldetect-current.tar.gz
cd maldetect-*/
sudo ./install.sh

# 4. Scan web directory immediately
sudo maldet -a /var/www/html

Done. LMD will scan and print the report to screen. If the output shows hits: X with X > 0, continue reading the section below to handle them.

Understanding What LMD and ClamAV Each Do

Many people install just one of them and think it’s enough — but they actually complement each other.

ClamAV is an antivirus engine with a database of millions of signatures, great at detecting viruses, trojans, and common malware. But ClamAV isn’t optimized for web shells — the most common type of malware found on web servers.

Linux Malware Detect (LMD) was built specifically for shared hosting and web servers. Its signatures are derived from real-world attacks against hosting environments — webshells, PHP backdoors, obfuscated code — the things ClamAV commonly misses.

When used together: LMD uses ClamAV as its scanning engine (for speed) while still applying its own signatures. Two layers of detection, one scan pass.

Configuring LMD Properly

The main config file is at /usr/local/maldetect/conf.maldet. I’ll cover the important options you need to change from the defaults:

sudo nano /usr/local/maldetect/conf.maldet
# Enable email alerts (replace with real email)
email_alert="1"
email_addr="[email protected]"

# Enable automatic quarantine — infected files are isolated, not deleted
quar_hits="1"
quar_clean="1"    # Try to clean before quarantining
quar_susp="0"     # Don't auto-quarantine "suspicious" files (prone to false positives)

# Use ClamAV as scanning engine (much faster)
clamav_scan="1"

# Real-time scanning with inotify (requires kernel support)
inotify_base="/var/www"
inotify_users="www-data"

# Limit scan to avoid hogging CPU
scan_max_filesize="2048"    # Skip files larger than 2MB
scan_tmpdir_paths="/tmp /var/tmp /dev/shm"  # Always scan tmp directories

After editing, restart the service:

sudo systemctl restart maldet

Configuring Daily Automatic Scans

LMD creates a cron job at /etc/cron.daily/maldet during installation, but by default it only scans /tmp and /var/tmp. Add your web directory:

sudo nano /etc/cron.daily/maldet

Find the line containing maldet and add the web path:

#!/bin/bash
/usr/local/maldetect/maldet -b -r /var/www/ 2>&1 | logger -t maldet

The -b flag runs in the background, -r for recursive scan. Results are written to syslog.

If you want weekly email reports instead of daily (to avoid inbox spam), create a separate cron job:

sudo crontab -e
# Deep scan at 3 AM every Sunday
0 3 * * 0 /usr/local/maldetect/maldet -a /var/www/ && /usr/local/maldetect/maldet --report REPORT_DATE

Handling Detected Malware

If the scan returns hits, here are the commands you need:

# View the most recent report
maldet --report

# View details of a specific report (YYYYMMDD-HHMMSS)
maldet --report 20240618-030000

# List quarantined files
ls -la /usr/local/maldetect/quarantine/

# Restore a file if it's a false positive
maldet -s /usr/local/maldetect/quarantine/FILENAME

# Clean (attempt to remove malware from file, keep the file)
maldet -c /path/to/file.php

In practice, I use -c for files that need to be preserved (like an injected WordPress plugin), and simply delete confirmed webshells after quarantine.

Advanced: Real-time Scanning with inotify

Instead of waiting for cron, LMD can monitor the filesystem in real time and scan immediately when files are created or modified:

# Check if the kernel supports inotify
ls /proc/sys/fs/inotify/
# If you see max_queued_events, max_user_instances, max_user_watches — you're good

# Increase inotify limits if needed (web servers with many files)
echo "fs.inotify.max_user_watches=524288" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# Start real-time monitoring
sudo maldet -m /var/www/

# Check if the monitor is running
sudo maldet --monitor-status

Note: real-time monitoring uses around 50–100MB of RAM depending on the number of files being watched. On small VPS instances (1GB RAM), consider monitoring only the upload directory rather than the entire web root.

Using ClamAV Daemon for Faster Scans

By default, ClamAV loads all signatures into RAM on every scan — which is slow. Use clamdscan with a resident daemon instead of clamscan:

# Enable clamav-daemon
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon

# Check daemon is running
sudo systemctl status clamav-daemon

# Test scan with daemon (significantly faster than clamscan)
clamdscan /var/www/html/suspicious-file.php

In the LMD config (conf.maldet), set clamav_scan="1" — LMD will automatically use clamdscan when the daemon is available.

Production Tips from Real-World Experience

Use strong passwords from the start. Most webshell infections happen through brute-forced FTP/SSH credentials or guessed WordPress passwords. I use the password generator at toolcraft.app/en/tools/security/password-generator to generate 32-character passwords for every account on the server — it runs entirely in the browser and sends nothing server-side, so there’s no interception risk.

Scan before restoring from backup. If your server was hacked and you’re restoring from an old backup, run LMD on the backup first — malware may have already been present before it was ever detected.

Whitelist false positives. LMD sometimes flags legitimate files (like Adminer or certain WordPress plugins). Add them to the whitelist rather than disabling the scan:

# Whitelist by file hash
maldet -w /var/www/html/adminer.php

# View the whitelist
cat /usr/local/maldetect/ignore/hex
cat /usr/local/maldetect/ignore/paths

Keep signatures updated automatically. LMD updates its signatures when it runs, but ClamAV needs freshclam. Check that freshclam is running:

sudo systemctl status clamav-freshclam
# If not running:
sudo systemctl enable --now clamav-freshclam

Centralize your logs. If you manage multiple servers, aggregate LMD logs in one place. I use logger in cron to push to syslog, then rsyslog forwards to a central log server. When an incident happens, you search one place instead of SSH-ing into each machine.

Quick Verification After Setup

# Create EICAR test file (harmless malware test string)
echo 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > /tmp/eicar-test.php

# Run the scan
maldet -a /tmp/eicar-test.php

# If output shows hits: 1, LMD + ClamAV are working correctly
# Clean up test file
rm /tmp/eicar-test.php

With this setup, you now have an active layer of protection. LMD isn’t a silver bullet — zero-day webshells and sophisticated obfuscated code can still slip through — but 95% of common attacks against shared hosting and WordPress will be blocked or detected before they cause serious damage.

Share: