AIDE (Advanced Intrusion Detection Environment) builds a cryptographic database of file attributes and checksums, then alerts you whenever a monitored file changes unexpectedly — a technique known as file integrity monitoring (FIM). On RHEL 9, AIDE is available in the standard repositories and integrates cleanly with systemd timers for scheduled checks and with auditd for correlating file change events with the processes that caused them. This tutorial covers installing AIDE, understanding its rule groups, customising the configuration to monitor your web files and system binaries while excluding volatile directories, initialising the reference database, running comparison checks, and automating daily scans with email alerts.
Prerequisites
- RHEL 9 server with a working MTA or relay configured (for email alerts)
- A non-root user with
sudoprivileges auditdinstalled and running (optional — for correlated security monitoring)- Sufficient disk space for the AIDE database (typically 50–200 MB depending on the monitored tree)
Step 1 — Install AIDE and Review the Default Configuration
Install AIDE from the RHEL 9 AppStream repository and review the default configuration file to understand the built-in rule groups before customising them.
sudo dnf install -y aide
# Check the installed version
aide --version
# Review the configuration file
sudo less /etc/aide.conf
# Default database paths defined in /etc/aide.conf:
# database_in=file:@@{DBDIR}/aide.db.gz <- reference (read from)
# database_out=file:@@{DBDIR}/aide.db.new.gz <- newly generated (write to)
# DBDIR=/var/lib/aide
ls -la /var/lib/aide/
Step 2 — Understand AIDE Rule Groups
AIDE uses named rule groups that combine multiple attribute checks. Understanding the built-in groups lets you choose the right level of monitoring granularity for each path — more attributes means more sensitivity but also more false positives from normal system activity.
# The key built-in rule groups defined in /etc/aide.conf are:
# CONTENT = sha512+md5
# Checks cryptographic checksums only — detects content changes but
# ignores ownership, permissions, and timestamp changes.
# CONTENT_EX = CONTENT+ftype+p+uname+gname
# Adds file type, permission bits, owner username, and group name
# to the content checks. Good for config files.
# Full = CONTENT_EX+mtime+atime+ctime
# Adds all three timestamps. Use sparingly — access time (atime)
# changes on every read and will generate constant alerts unless
# the filesystem is mounted with noatime.
# View all defined macros in the config
sudo grep -E '^[A-Z_]+ =' /etc/aide.conf | head -30
Step 3 — Customise /etc/aide.conf with Your Monitoring Rules
Append custom monitoring rules for your web document root and any application directories, then explicitly exclude volatile runtime directories that change constantly to avoid false positives.
sudo cp /etc/aide.conf /etc/aide.conf.bak
sudo tee -a /etc/aide.conf > /dev/null <<'EOF'
# -----------------------------------------------------------------------
# Custom monitoring rules — appended below the defaults
# -----------------------------------------------------------------------
# Web document root: monitor content and attributes (not timestamps)
/var/www/html CONTENT_EX
# Application configuration files
/etc/nginx CONTENT_EX
/etc/php.ini CONTENT_EX
/etc/php.d CONTENT_EX
# WordPress core files (adjust path to match your installation)
/var/www/html/wp-includes CONTENT_EX
/var/www/html/wp-admin CONTENT_EX
# -----------------------------------------------------------------------
# Exclusions — volatile directories that change constantly
# -----------------------------------------------------------------------
!/var/log
!/proc
!/sys
!/dev
!/run
!/tmp
!/var/tmp
!/var/cache
!/var/spool
!/var/lib/aide
EOF
# Validate config syntax
sudo aide --config-check
Step 4 — Initialize the AIDE Reference Database
Run aide --init to build the baseline database. This is the snapshot against which all future checks are compared — run it on a known-good system state.
# Initialise the database (may take several minutes on large filesystems)
sudo aide --init
# The new database is written to /var/lib/aide/aide.db.new.gz
ls -lh /var/lib/aide/
# Promote the new database to become the active reference database
sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
# For maximum security, copy the reference database to a read-only
# or external location immediately after initialisation
# Example: copy to a mounted read-only NFS share or USB device
# sudo cp /var/lib/aide/aide.db.gz /mnt/readonly-store/aide.db.gz
Step 5 — Run a Comparison Check and Interpret the Output
Run aide --check to compare the current filesystem state against the reference database. AIDE reports added, removed, and changed files along with which attributes changed.
# Run a full check against the reference database
sudo aide --check 2>&1 | tee /var/log/aide/aide-check-$(date +%F).log
# AIDE exit codes:
# 0 — no changes found
# 1 — new files found
# 2 — removed files found
# 4 — changed files found (codes are additive, so 6 = removed + changed)
echo "AIDE exit code: $?"
# To compare against a database stored on a read-only mount
# (overriding the path defined in /etc/aide.conf at runtime):
sudo aide --check
--config=/etc/aide.conf
--before="database_in=file:/mnt/readonly-store/aide.db.gz"
# After planned system updates, re-initialise the database so the
# new state becomes the reference baseline
sudo aide --update
sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
Step 6 — Automate Daily Checks with a Systemd Timer and Email Alerts
Create a systemd service and timer to run aide --check daily and email the results to the system administrator. This replaces the traditional cron approach and integrates with the systemd journal for logging.
sudo mkdir -p /var/log/aide
sudo tee /usr/local/bin/aide-check-and-alert.sh > /dev/null <&1 | tee "$LOGFILE"
EXIT_CODE=${PIPESTATUS[0]}
if [[ $EXIT_CODE -ne 0 ]]; then
mail -s "AIDE Alert: filesystem changes detected on $(hostname)"
"$ADMIN_EMAIL" /dev/null < /dev/null <<'EOF'
[Unit]
Description=Daily AIDE File Integrity Check
[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=1800
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now aide-check.timer
# Check the timer is scheduled
systemctl list-timers aide-check.timer
Conclusion
AIDE is now installed on RHEL 9 with a customised rule set that monitors your web root, application configuration files, and critical system binaries using checksum and attribute verification, while excluding volatile directories to keep the daily reports actionable. The systemd timer fires once a day with a randomised delay to avoid all servers reporting simultaneously, and the shell script emails a diff to the administrator whenever unexpected changes are detected. For a defence-in-depth setup, combine AIDE alerts with auditd key-tagged rules on the same paths — when AIDE detects a change, the corresponding ausearch output will tell you exactly which process and user made it.
Next steps: How to Configure auditd for Security Event Logging on RHEL 9, How to Set Up Tripwire for Advanced File Integrity Monitoring on RHEL 9, and How to Integrate AIDE Alerts with a SIEM Using rsyslog on RHEL 9.