Generate comprehensive CSV and JSON reports of all DirectAdmin accounts, domains, quotas, and configurations.
The da_report.sh script provides automated reporting capabilities for DirectAdmin installations, generating detailed inventories of:
- User accounts and quotas
- Domain listings and ownership
- PHP versions per account
- Hostname/IP resolution
- Disk space usage
This supports NIS2 compliance by maintaining an asset inventory of your DNS infrastructure.
- Multiple Output Formats: CSV (default) and JSON
- Comprehensive Data: Account, quota, domain, PHP version, hostname
- Environment Overrides: Configurable via environment variables
- Error Handling: Robust error checking and logging
- Production Ready: Safe defaults, proper escaping, logging
# Copy to system PATH
sudo cp scripts/da_report.sh /usr/local/bin/da_report
sudo chmod +x /usr/local/bin/da_report
# Verify installation
da_report --help# Place script in custom location
sudo mkdir -p /opt/directadmin/scripts
sudo cp scripts/da_report.sh /opt/directadmin/scripts/
sudo chmod +x /opt/directadmin/scripts/da_report.sh
# Create symlink
sudo ln -s /opt/directadmin/scripts/da_report.sh /usr/local/bin/da_report# Generate default CSV report (current directory)
sudo da_report
# Output: da_report_20251029_143215.csv# Specify output file
sudo da_report -o /var/reports/domains.csv
# With timestamp
sudo da_report -o /var/reports/domains_$(date +%Y%m%d).csv# Generate JSON report
sudo da_report --json
# Output: da_report_20251029_143215.json
# JSON with custom path
sudo da_report --json -o /var/reports/domains.json# Display usage information
da_report --help| Option | Long Form | Description |
|---|---|---|
-o FILE |
--output FILE |
Specify output file path |
-j |
--json |
Output in JSON format (requires jq) |
-h |
--help |
Display help message |
Configure the script using environment variables:
# DirectAdmin CLI path (default: /usr/local/directadmin/dataskq)
export DA_ADMIN_CLI="/usr/local/directadmin/dataskq"
# DirectAdmin data directory (default: /usr/local/directadmin/data)
export DA_DATA_DIR="/usr/local/directadmin/data"# Default output directory (default: current directory)
export OUTPUT_DIR="/var/reports/directadmin"# Create configuration file
sudo tee /etc/default/da-reports <<EOF
DA_ADMIN_CLI="/usr/local/directadmin/dataskq"
DA_DATA_DIR="/usr/local/directadmin/data"
OUTPUT_DIR="/var/reports/directadmin"
EOF
# Source before running
source /etc/default/da-reports
da_reportHeader:
account,space_kb,domain,domain_php_version,hostnameExample Rows:
user1,524288,example.com,php80,192.0.2.1
user1,524288,shop.example.com,php80,192.0.2.1
user2,1048576,another.com,php74,192.0.2.50
user2,1048576,blog.another.com,php74,192.0.2.50
admin,2097152,server.example.com,default,192.0.2.100Fields:
| Field | Description | Example |
|---|---|---|
account |
DirectAdmin username | user1 |
space_kb |
Disk quota in kilobytes | 524288 (512 MB) |
domain |
Domain name | example.com |
domain_php_version |
PHP version (user default) | php80, php74, default |
hostname |
Resolved IP address | 192.0.2.1, unresolved |
Example:
[
{
"account": "user1",
"space_kb": "524288",
"domain": "example.com",
"domain_php_version": "php80",
"hostname": "192.0.2.1"
},
{
"account": "user2",
"space_kb": "1048576",
"domain": "another.com",
"domain_php_version": "php74",
"hostname": "192.0.2.50"
}
]#!/bin/bash
# /etc/cron.daily/da-report
OUTPUT_DIR="/var/reports/directadmin"
TIMESTAMP=$(date +%Y%m%d)
# Generate CSV report
/usr/local/bin/da_report -o "${OUTPUT_DIR}/domains_${TIMESTAMP}.csv"
# Generate JSON report
/usr/local/bin/da_report --json -o "${OUTPUT_DIR}/domains_${TIMESTAMP}.json"
# Clean up old reports (keep 90 days)
find "$OUTPUT_DIR" -name "domains_*.csv" -mtime +90 -delete
find "$OUTPUT_DIR" -name "domains_*.json" -mtime +90 -delete#!/bin/bash
# /etc/cron.weekly/da-report-email
REPORT_FILE="/tmp/da_domains_$(date +%Y%m%d).csv"
ADMIN_EMAIL="admin@example.com"
# Generate report
da_report -o "$REPORT_FILE"
# Count domains and accounts
ACCOUNT_COUNT=$(tail -n +2 "$REPORT_FILE" | cut -d, -f1 | sort -u | wc -l)
DOMAIN_COUNT=$(tail -n +2 "$REPORT_FILE" | wc -l)
# Send email with attachment
{
echo "Subject: Weekly DirectAdmin Report"
echo "To: $ADMIN_EMAIL"
echo "Content-Type: text/plain; charset=UTF-8"
echo ""
echo "Weekly DirectAdmin Domain Report"
echo "================================"
echo ""
echo "Total Accounts: $ACCOUNT_COUNT"
echo "Total Domains: $DOMAIN_COUNT"
echo ""
echo "Full report attached."
} | sendmail -t
# Cleanup
rm -f "$REPORT_FILE"#!/bin/bash
# Send report to monitoring system
# Generate JSON report
REPORT_FILE="/tmp/da_report_$(date +%s).json"
da_report --json -o "$REPORT_FILE"
# Send to monitoring API
curl -X POST https://monitoring.example.com/api/directadmin \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN" \
--data-binary "@${REPORT_FILE}"
# Cleanup
rm -f "$REPORT_FILE"#!/bin/bash
# Analyze domains per account
CSV_FILE="$(da_report -o /tmp/da_report.csv 2>&1 | grep 'Output file:' | awk '{print $3}')"
echo "Domains per Account:"
echo "===================="
tail -n +2 "$CSV_FILE" | \
cut -d, -f1 | \
sort | \
uniq -c | \
sort -rn | \
awk '{printf "%-20s %d domains\n", $2, $1}'The script extracts data from DirectAdmin's filesystem:
# Via DirectAdmin CLI
echo "CMD_API_SHOW_USERS" | /usr/local/directadmin/dataskq# File: /usr/local/directadmin/data/users/<username>/user.usage
# Format: quota=524288# File: /usr/local/directadmin/data/users/<username>/domains.list
# Format: One domain per line# File: /usr/local/directadmin/data/users/<username>/user.conf
# Format: php1_select=php80# Using 'dig' command
dig +short example.com A | head -n1Problem: Cannot read DirectAdmin CLI
Solution:
# Run with sudo
sudo da_report
# Or add current user to directadmin group
sudo usermod -aG directadmin $(whoami)Problem: Report generated but no data
Solutions:
# 1. Verify DirectAdmin CLI path
ls -l /usr/local/directadmin/dataskq
# 2. Test CLI directly
echo "CMD_API_SHOW_USERS" | sudo /usr/local/directadmin/dataskq
# 3. Check data directory
ls -la /usr/local/directadmin/data/users/
# 4. Verify script has execute permission
chmod +x /usr/local/bin/da_reportProblem: jq is required for JSON output but not found
Solution:
# RHEL/CentOS/Rocky:
sudo yum install jq
# Debian/Ubuntu:
sudo apt-get install jq
# Verify installation
jq --versionProblem: Report generation takes too long
Cause: DNS resolution for each domain
Solution:
# Skip hostname resolution by modifying script
# Comment out the get_domain_hostname call
# Or set a timeout for dig
# Alternative: Generate report without hostnames,
# then resolve in parallel batch:
tail -n +2 report.csv | cut -d, -f3 | \
xargs -P 10 -I {} dig +short {} AProblem: CSV contains commas in fields
Solution: The script properly escapes CSV fields. Ensure you're using a CSV-aware parser:
# Python
import csv
with open('report.csv') as f:
reader = csv.DictReader(f)
for row in reader:
print(row)
# awk (with proper CSV support)
awk -F',' '{print $1}' report.csv # May break on quoted fields
# Use csvkit instead
csvcut -c account report.csv# Generate report, filter for specific user
da_report -o /tmp/all_domains.csv
grep "^user1," /tmp/all_domains.csv# Sum all disk usage
tail -n +2 report.csv | \
cut -d, -f2 | \
awk '{sum+=$1} END {print sum/1024/1024 " GB"}'# List domains with no DNS resolution
tail -n +2 report.csv | \
grep ",unresolved$" | \
cut -d, -f3#!/bin/bash
# Import CSV into PostgreSQL
REPORT_FILE=$(da_report -o /tmp/da_report.csv 2>&1 | grep 'Output file' | awk '{print $3}')
psql -U admin -d inventory <<SQL
CREATE TABLE IF NOT EXISTS directadmin_domains (
account VARCHAR(255),
space_kb BIGINT,
domain VARCHAR(255),
php_version VARCHAR(50),
hostname VARCHAR(255),
report_date DATE DEFAULT CURRENT_DATE
);
COPY directadmin_domains(account, space_kb, domain, php_version, hostname)
FROM '${REPORT_FILE}'
WITH (FORMAT csv, HEADER true);
SQLNIS2 Directive requires organizations to maintain an up-to-date inventory of assets. This script helps fulfill that requirement for DNS infrastructure.
- Regular Reporting: Generate reports daily or weekly
- Version Control: Store reports in version-controlled repository
- Change Detection: Compare reports to detect additions/removals
- Documentation: Document reporting procedures in your ISMS
- Retention: Keep reports according to regulatory retention periods
#!/bin/bash
# NIS2 Asset Inventory - Daily Report
REPORT_DIR="/var/compliance/nis2/asset-inventory"
DATE=$(date +%Y%m%d)
PREVIOUS_REPORT=$(ls -t $REPORT_DIR/domains_*.csv 2>/dev/null | head -n1)
# Generate current report
CURRENT_REPORT="${REPORT_DIR}/domains_${DATE}.csv"
da_report -o "$CURRENT_REPORT"
# If previous report exists, compare
if [ -n "$PREVIOUS_REPORT" ]; then
DIFF_FILE="${REPORT_DIR}/changes_${DATE}.diff"
diff "$PREVIOUS_REPORT" "$CURRENT_REPORT" > "$DIFF_FILE"
if [ -s "$DIFF_FILE" ]; then
# Changes detected, send alert
mail -s "NIS2 Asset Inventory Changes Detected" \
compliance@example.com < "$DIFF_FILE"
fi
fi
# Git commit for version control
cd "$REPORT_DIR"
git add "$CURRENT_REPORT"
git commit -m "Daily asset inventory - $DATE"Typical performance on a server with 100 accounts and 500 domains:
- CSV Generation: ~30 seconds
- JSON Generation: ~35 seconds (includes jq formatting)
Performance factors:
- Number of accounts/domains
- DNS resolution time (major factor)
- Disk I/O speed
- CPU performance
- Cache DNS Results: Cache hostname resolutions to speed up subsequent runs
- Parallel Processing: Modify script to resolve hostnames in parallel
- Skip Hostname Resolution: Comment out hostname lookup for faster reports
- Run During Off-Peak: Schedule reports during low-traffic periods
#!/bin/bash
# Export metrics for Prometheus
REPORT_FILE="/tmp/da_metrics.csv"
da_report -o "$REPORT_FILE"
ACCOUNT_COUNT=$(tail -n +2 "$REPORT_FILE" | cut -d, -f1 | sort -u | wc -l)
DOMAIN_COUNT=$(tail -n +2 "$REPORT_FILE" | wc -l)
TOTAL_SPACE=$(tail -n +2 "$REPORT_FILE" | cut -d, -f2 | awk '{sum+=$1} END {print sum}')
cat <<EOF > /var/lib/node_exporter/textfile_collector/directadmin.prom
# HELP directadmin_accounts Total number of DirectAdmin accounts
# TYPE directadmin_accounts gauge
directadmin_accounts $ACCOUNT_COUNT
# HELP directadmin_domains Total number of domains
# TYPE directadmin_domains gauge
directadmin_domains $DOMAIN_COUNT
# HELP directadmin_space_kb Total disk space usage in KB
# TYPE directadmin_space_kb gauge
directadmin_space_kb $TOTAL_SPACE
EOFUse the JSON output with Grafana's JSON data source:
# Generate JSON for Grafana
da_report --json -o /var/www/html/api/directadmin/domains.json
# Configure Grafana JSON data source:
# URL: http://yourserver.com/api/directadmin/domains.json- Main README: ../README.md
- DNS Monitoring: dns_change_notifications.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