Real-time email alerts for DNS zone modifications in DirectAdmin
The DNS Change Notification system uses DirectAdmin custom hooks to detect DNS zone modifications and automatically email domain owners with detailed before/after comparisons. This provides immediate visibility into DNS changes for security and compliance purposes.
┌─────────────────────────────────────────────────────────────┐
│ Admin edits DNS via DirectAdmin Control Panel │
└─────────────────────┬───────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ all_pre.sh (Pre-Hook) │
│ • Triggered before DNS save │
│ • Detects CMD_DNS_ADMIN / CMD_DNS_CONTROL │
│ • Backs up current zone file to timestamped location │
│ • Creates marker file with backup path │
└─────────────────────┬───────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ DirectAdmin writes new zone file │
│ /var/named/domain.db (updated) │
└─────────────────────┬───────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ dns_write_post.sh (Post-Hook) │
│ • Triggered after DNS save │
│ • Reads backup marker to find old zone │
│ • Generates unified diff (old vs new) │
│ • Filters out SOA-only changes (serial updates) │
│ • Determines domain owner via /etc/virtual/domainowners │
│ • Reads owner email from user.conf │
│ • Sends email notification with diff │
│ • Logs action for audit trail │
└─────────────────────┬───────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Domain owner receives email: │
│ Subject: [DNS ALERT] DNS Changes for domain.com │
│ Body: Unified diff + security notice + compliance info │
└─────────────────────────────────────────────────────────────┘
- DirectAdmin installed (version 1.60+)
- Root or admin access
- Mail system configured (
mailorsendmailcommand) - Bash 4.0+
# Create custom hooks directory
sudo mkdir -p /usr/local/directadmin/scripts/custom
# Copy hook scripts
sudo cp scripts/dns/all_pre.sh \
scripts/dns/dns_write_post.sh \
/usr/local/directadmin/scripts/custom/
# Set executable permissions
sudo chmod 755 /usr/local/directadmin/scripts/custom/all_pre.sh
sudo chmod 755 /usr/local/directadmin/scripts/custom/dns_write_post.sh# Backup storage
sudo mkdir -p /var/local/da_dns_backups
sudo chmod 755 /var/local/da_dns_backups
# Log directory
sudo mkdir -p /var/log/da-hooks
sudo chmod 755 /var/log/da-hooks# Test mail command
echo "Test email from DirectAdmin DNS Alert System" | \
mail -s "Test Subject" your-email@example.com
# If mail is not available, install it:
# RHEL/CentOS/Rocky:
sudo yum install mailx
# Debian/Ubuntu:
sudo apt-get install mailutils# Manually trigger pre-hook
sudo domain=test.com \
command=CMD_DNS_ADMIN \
action=save \
/usr/local/directadmin/scripts/custom/all_pre.sh
# Check logs
sudo cat /var/log/da-hooks/dns_backup.log
# Verify backup was created
sudo ls -lh /var/local/da_dns_backups/Configure the hooks using environment variables in /etc/default/da-dns-alerts:
# Create configuration file
sudo tee /etc/default/da-dns-alerts <<'EOF'
# Zone file directory
ZONE_DIR="/var/named" # or /etc/bind for Debian
# Backup storage
DNS_BACKUP_DIR="/var/local/da_dns_backups"
# Log file
DNS_HOOK_LOG="/var/log/da-hooks/dns_notify.log"
# Enable/disable email notifications
DNS_SEND_EMAIL="true"
# Email from address
DNS_EMAIL_FROM="dns-alert@example.com"
# Email subject prefix
DNS_EMAIL_SUBJECT_PREFIX="[DNS ALERT]"
# Maximum diff lines in email (truncate if exceeded)
DNS_MAX_DIFF_LINES="500"
# Backup retention in days
DNS_BACKUP_RETENTION="7"
# DirectAdmin paths
DA_CONF="/usr/local/directadmin/conf/directadmin.conf"
DA_DATA_DIR="/usr/local/directadmin/data"
DOMAIN_OWNERS="/etc/virtual/domainowners"
EOF
# Set permissions
sudo chmod 644 /etc/default/da-dns-alertsTo use custom configuration, edit the hook scripts:
# Edit all_pre.sh
sudo nano /usr/local/directadmin/scripts/custom/all_pre.sh
# Add configuration sourcing at the top (after shebang):
if [ -f /etc/default/da-dns-alerts ]; then
. /etc/default/da-dns-alerts
fi
# Repeat for dns_write_post.sh[DNS ALERT] DNS Changes for example.com
DNS Zone Change Notification
============================
DOMAIN: example.com
MODIFIED BY: admin
TIMESTAMP: 2025-10-29 14:32:15 UTC
SERVER: server.example.com
SECURITY NOTICE:
If you did not authorize this change, please contact your hosting
administrator immediately. Unauthorized DNS changes may indicate
a security incident.
NIS2 COMPLIANCE:
This notification is part of your DNS infrastructure's audit trail,
supporting governance requirements under EU NIS2 Directive 2022/2555.
--------------------------------------------------------------------------------
DNS ZONE CHANGES (Unified Diff)
--------------------------------------------------------------------------------
Legend:
Lines starting with '-' show REMOVED/OLD records
Lines starting with '+' show ADDED/NEW records
Unchanged lines provide context
--- /var/local/da_dns_backups/example.com.20251029_143000.db 2025-10-29 14:30:00
+++ /var/named/example.com.db 2025-10-29 14:32:15
@@ -8,12 +8,12 @@
$TTL 14400
@ IN SOA ns1.example.com. hostmaster.example.com. (
- 2025102901 ; serial
+ 2025102902 ; serial
14400 ; refresh
3600 ; retry
1209600 ; expire
86400 ) ; minimum
@ IN NS ns1.example.com.
@ IN NS ns2.example.com.
-www IN A 192.0.2.1
+www IN A 192.0.2.100
ftp IN A 192.0.2.2
+mail IN A 192.0.2.50
@ IN MX 10 mail.example.com.
--------------------------------------------------------------------------------
NEXT STEPS:
1. Review the changes above carefully
2. Verify all modifications are authorized
3. Update your documentation if needed
4. Report any suspicious changes immediately
For questions or concerns, contact your hosting provider.
---
Generated by DirectAdmin DNS Change Monitor
ITCMS DNS Alert System - https://itcms.gr
Copyright © 2025 Antonios Voulvoulis, ITCMS.GR
The unified diff format shows changes using these symbols:
| Symbol | Meaning | Example |
|---|---|---|
- |
Removed line (OLD value) | -www IN A 192.0.2.1 |
+ |
Added line (NEW value) | +www IN A 192.0.2.100 |
@@ -8,12 +8,12 @@ |
Line numbers (old file lines 8-12, new file lines 8-12) | Context for changes |
| (space) | Unchanged line (context) | ftp IN A 192.0.2.2 |
-
Map domain to username:
grep "^example.com:" /etc/virtual/domainowners # Output: example.com: user1
-
Get user's email:
grep "^email=" /usr/local/directadmin/data/users/user1/user.conf # Output: email=user@example.com
-
Fallback to admin email (if owner email not found):
grep "^admin_email=" /usr/local/directadmin/conf/directadmin.conf # Output: admin_email=admin@server.com
# Test domain ownership lookup
DOMAIN="example.com"
OWNER=$(grep "^${DOMAIN}:" /etc/virtual/domainowners | cut -d: -f2)
echo "Domain: $DOMAIN, Owner: $OWNER"
# Test email lookup
EMAIL=$(grep "^email=" /usr/local/directadmin/data/users/$OWNER/user.conf | cut -d= -f2)
echo "Owner Email: $EMAIL"For DirectAdmin Multi-Server DNS configurations, use the additional dns_raw_save_post.sh hook:
# Install cluster hook
sudo cp scripts/dns/dns_raw_save_post.sh \
/usr/local/directadmin/scripts/custom/
sudo chmod 755 /usr/local/directadmin/scripts/custom/dns_raw_save_post.sh# Add cluster configuration to /etc/default/da-dns-alerts
echo 'DA_SERVER_ROLE="secondary"' | sudo tee -a /etc/default/da-dns-alerts
echo 'DA_CLUSTER_NAME="production-cluster"' | sudo tee -a /etc/default/da-dns-alertsUse dns_raw_save_post.sh when:
- You have DirectAdmin Multi-Server DNS enabled
- DNS zones are synchronized from primary to secondary servers
- You want notifications on secondary/slave nameservers
Symptoms: DNS changes occur but no emails received
Diagnosis:
# 1. Check if hook is being triggered
sudo tail -f /var/log/da-hooks/dns_notify.log
# Expected output when DNS is modified:
# [2025-10-29 14:32:15] INFO: DNS write post-hook triggered for domain: example.com
# [2025-10-29 14:32:15] INFO: Sending DNS change notification for example.com to user@example.com
# [2025-10-29 14:32:16] Notification sent via 'mail' to user@example.com for domain example.com
# 2. Check for errors
sudo grep ERROR /var/log/da-hooks/dns_notify.log
# 3. Verify mail system
echo "Test" | mail -s "Test" your@email.com
# 4. Check if emails are disabled
grep DNS_SEND_EMAIL /etc/default/da-dns-alertsSolutions:
# Solution 1: Enable email notifications
echo 'DNS_SEND_EMAIL="true"' | sudo tee -a /etc/default/da-dns-alerts
# Solution 2: Install mail command
# RHEL/CentOS:
sudo yum install mailx
# Debian/Ubuntu:
sudo apt-get install mailutils
# Solution 3: Check backup marker
sudo ls -la /var/local/da_dns_backups/*.last_backup
# Solution 4: Manually test post-hook
sudo domain=example.com username=admin \
DNS_SEND_EMAIL=true \
/usr/local/directadmin/scripts/custom/dns_write_post.shSymptoms: No log entries when DNS is modified
Diagnosis:
# 1. Verify hooks are installed
ls -lh /usr/local/directadmin/scripts/custom/
# Expected output:
# -rwxr-xr-x 1 root root 4.2K all_pre.sh
# -rwxr-xr-x 1 root root 8.1K dns_write_post.sh
# 2. Check permissions
stat /usr/local/directadmin/scripts/custom/all_pre.sh
# Should show: Access: (0755/-rwxr-xr-x)
# 3. Test for syntax errors
sudo bash -n /usr/local/directadmin/scripts/custom/all_pre.sh
sudo bash -n /usr/local/directadmin/scripts/custom/dns_write_post.shSolutions:
# Solution 1: Fix permissions
sudo chmod 755 /usr/local/directadmin/scripts/custom/*.sh
# Solution 2: Verify DirectAdmin hook system
# Check DirectAdmin logs
sudo tail -f /var/log/directadmin/error.log
# Solution 3: Manually trigger hooks
sudo domain=test.com command=CMD_DNS_ADMIN action=save \
/usr/local/directadmin/scripts/custom/all_pre.shSymptoms: dns_write_post.sh logs "No backup marker found"
Diagnosis:
# 1. Check pre-hook logs
sudo cat /var/log/da-hooks/dns_backup.log
# 2. Verify backup directory permissions
ls -ld /var/local/da_dns_backups
# Should show: drwxr-xr-x
# 3. Check zone file path
ls -la /var/named/*.db # RHEL/CentOS
ls -la /etc/bind/*.db # Debian/UbuntuSolutions:
# Solution 1: Create backup directory
sudo mkdir -p /var/local/da_dns_backups
sudo chmod 755 /var/local/da_dns_backups
# Solution 2: Fix zone directory path (Debian/Ubuntu)
sudo sed -i 's|/var/named|/etc/bind|g' \
/usr/local/directadmin/scripts/custom/all_pre.sh \
/usr/local/directadmin/scripts/custom/dns_write_post.sh
# Solution 3: Manually test pre-hook
sudo domain=example.com command=CMD_DNS_ADMIN action=save \
/usr/local/directadmin/scripts/custom/all_pre.sh
# Verify backup created
sudo ls -lh /var/local/da_dns_backups/Symptoms: Email not sent even though zone was modified
Explanation: The post-hook filters out changes that only affect SOA serial numbers, as these occur with every save and don't represent meaningful DNS changes.
Diagnosis:
# Check logs for "No meaningful DNS changes" message
sudo grep "No meaningful" /var/log/da-hooks/dns_notify.logExpected Behavior: This is intentional. Notifications are suppressed for serial-only changes to avoid spam.
To Change: Modify dns_write_post.sh and remove/comment out the SOA filtering logic around line 150.
Symptoms: Email sent to admin instead of domain owner
Diagnosis:
# Check domain ownership
DOMAIN="example.com"
grep "^${DOMAIN}:" /etc/virtual/domainowners
# Check user email
OWNER=$(grep "^${DOMAIN}:" /etc/virtual/domainowners | cut -d: -f2)
cat /usr/local/directadmin/data/users/$OWNER/user.conf | grep emailSolutions:
# Solution 1: Update domain owner email in DirectAdmin
# Log into DirectAdmin as reseller/admin
# User Level -> Manage User -> Modify User -> Email
# Solution 2: Manually fix user.conf
sudo nano /usr/local/directadmin/data/users/username/user.conf
# Set: email=correct@email.com
# Solution 3: Verify domainowners file
sudo cat /etc/virtual/domainowners | grep example.com
# Should show: example.com: usernameModify dns_write_post.sh to customize the email format:
sudo nano /usr/local/directadmin/scripts/custom/dns_write_post.sh
# Find the email_body section (around line 180)
# Customize the cat <<EOF sectionAdd logic to suppress notifications for specific domains or users:
# In dns_write_post.sh, after domain validation:
# Suppress notifications for specific domains
if [[ "$domain" == "internal.example.com" ]]; then
log_info "Notifications suppressed for internal domain: $domain"
exit 0
fi
# Suppress for specific users
if [[ "$username" == "monitoring" ]]; then
log_info "Notifications suppressed for user: $username"
exit 0
fiSend notifications to multiple email addresses:
# In dns_write_post.sh, modify the email sending section:
# Add CC recipients
ADDITIONAL_RECIPIENTS="dns-team@example.com,security@example.com"
echo "$email_body" | mail -s "$email_subject" \
-r "$EMAIL_FROM" \
-c "$ADDITIONAL_RECIPIENTS" \
"$recipient_email"Add webhook notifications (Slack, Teams, Discord):
# In dns_write_post.sh, after email is sent:
# Slack webhook
SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
curl -X POST "$SLACK_WEBHOOK" \
-H 'Content-Type: application/json' \
-d "{\"text\": \"DNS changed for $domain by $modified_by\"}"
# Microsoft Teams
TEAMS_WEBHOOK="https://your-tenant.webhook.office.com/..."
curl -X POST "$TEAMS_WEBHOOK" \
-H 'Content-Type: application/json' \
-d "{\"text\": \"DNS Alert: $domain modified by $modified_by\"}"- Unencrypted Email: Notifications are sent via standard email (plaintext)
- Sensitive Data: DNS records may contain internal infrastructure details
- Recommendation: For highly sensitive environments, consider:
- PGP/GPG encryption for emails
- Webhook notifications to internal systems
- HTTPS-based notification delivery
- Backup Storage: Contains full DNS zones with all records
- Access Control: Restrict access to
/var/local/da_dns_backups/ - Retention: Configure appropriate retention period (default: 7 days)
# Secure backup directory
sudo chmod 700 /var/local/da_dns_backups
sudo chown root:root /var/local/da_dns_backups
# Set up automatic cleanup
echo "0 3 * * * find /var/local/da_dns_backups -name '*.db' -mtime +7 -delete" | \
sudo crontab -- Log Contents: May contain usernames, domains, IP addresses
- Access Control: Restrict log file access
# Secure log directory
sudo chmod 750 /var/log/da-hooks
sudo chown root:adm /var/log/da-hooks
# Set up log rotation
sudo tee /etc/logrotate.d/da-hooks <<EOF
/var/log/da-hooks/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 640 root adm
}
EOF# Check for recent notifications
sudo tail -20 /var/log/da-hooks/dns_notify.log
# Count notifications per day
sudo grep "Notification sent" /var/log/da-hooks/dns_notify.log | \
cut -d' ' -f1 | cut -d'[' -f2 | cut -d' ' -f1 | sort | uniq -c
# Monitor for errors
sudo tail -f /var/log/da-hooks/dns_notify.log | grep ERROR#!/bin/bash
# /etc/cron.hourly/check-dns-hooks
LOG_FILE="/var/log/da-hooks/dns_notify.log"
ERROR_COUNT=$(grep -c "ERROR" "$LOG_FILE")
if [ "$ERROR_COUNT" -gt 0 ]; then
tail -20 "$LOG_FILE" | grep ERROR | \
mail -s "DNS Hook Errors Detected" admin@example.com
fiThe DNS notification system provides:
- Change Detection: Real-time notification of DNS modifications
- Attribution: Records who made changes (admin username)
- Timestamping: Exact time of modification
- Change Details: Complete before/after comparison
- Retention: Configurable backup retention for audit purposes
For NIS2 compliance, document:
- System Description: How DNS monitoring works
- Notification Procedures: Who receives alerts and how
- Retention Policies: How long backups and logs are kept
- Incident Response: What to do when unauthorized changes are detected
- Testing: Regular testing procedures
- Main README: ../README.md
- Reporting Guide: da_report.md
- NIS2 Compliance: NIS2.md
- Email: contact@itcms.gr
- Support: support@itcms.gr
- Website: https://itcms.gr
Copyright © 2025 Antonios Voulvoulis, ITCMS.GR Licensed under ITCMS.GR Free License SPDX-License-Identifier: LicenseRef-ITCMS-Free-1.0
Part of the DirectAdmin DNS Change Alert System https://itcms.gr