How to install and schedule server_audit_notify.sh
Download the script to /usr/local/bin, store your SMTP password in a file only root can read, run the script once as root, and then schedule it with cron or a systemd timer.
Requirements
The script is written for Debian, Ubuntu and Red Hat style systems. The FAQ covers other systems.
| Requirement | Why the script needs it |
|---|---|
| Root access | It writes to /var/log/server_audit, installs missing packages, reads system logs and searches the file system. |
| Bash | The script uses Bash syntax such as [[ ]] and arrays. |
curl and lynis | It installs either one with apt-get or yum if it is missing. On other systems, install both yourself. |
ss or netstat | Used for the listening ports check. Without either, the script skips that check and says so in the report. |
| SSH logs | It reads /var/log/auth.log, then /var/log/secure, then the journal with journalctl -u ssh -u sshd. |
| An SMTP account | A username and password for an SMTP server that supports TLS. The default is smtp.forwardemail.net on port 465. |
Installation steps
1. Install the prerequisites
Install Lynis and curl. The script would install them on its own, but installing them first keeps the first run short.
# Debian and Ubuntu
apt-get update
apt-get install -y lynis curl
# Red Hat style systems (Lynis may need the EPEL repository)
yum install -y lynis curl
2. Download the script
Save the script to /usr/local/bin and make it executable. Read it before you run it as root; the checks page explains each part.
curl -fsSL -o /usr/local/bin/server_audit_notify.sh \
https://raw.githubusercontent.com/forwardemail/serverauditing.com/main/server_audit_notify.sh
chmod 755 /usr/local/bin/server_audit_notify.sh
less /usr/local/bin/server_audit_notify.sh
3. Get SMTP credentials
With Forward Email, outbound SMTP comes with all paid plans. Create an alias for the sender, use its full address as the username, and create a password with the alias "Generate Password" option. The SMTP section of the Forward Email FAQ covers setup.
For another provider, pass --smtp and --port. Ports 465 and 2465 use implicit TLS, and any other port uses STARTTLS. The script always requires TLS and verifies the server certificate.
4. Store the password in a root-only file
Put the password on the first line of a file that only root can read. The script refuses a password file that its group or other users can read.
install -m 600 /dev/null /root/.server-audit-pass
printf '%s\n' 'your-smtp-password' > /root/.server-audit-pass
You can also set the SMTP_PASS environment variable. The old --pass option still works, but the password is then visible in the process list, and the script prints a warning.
5. Run a test audit
Run the script once by hand and watch the output. It creates /var/log/server_audit with mode 700 if it does not exist.
/usr/local/bin/server_audit_notify.sh \
--email ops@example.com \
--user alerts@example.com \
--pass-file /root/.server-audit-pass
Check that the files appear in /var/log/server_audit (the file list shows what to expect) and that the email arrives. The script exits with status 0 on success, 1 when the email fails, and 2 when an option is missing or wrong.
6. Schedule a daily run with cron
Cron starts jobs with a short PATH, so set it in the file. That way the script finds lynis and ss, which often live in /usr/sbin or /sbin.
cat > /etc/cron.d/server-audit <<'EOF'
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
15 6 * * * root /usr/local/bin/server_audit_notify.sh --quiet --email ops@example.com --user alerts@example.com --pass-file /root/.server-audit-pass
EOF
Add --only-on-issues if you want an email only when the audit finds Lynis warnings, failed SSH logins or a file system at 90% or more.
7. Or schedule it with a systemd timer
A systemd timer logs each run to the journal and can catch up after downtime with Persistent=true. A failed email makes the service fail, so systemctl --failed shows it.
# /etc/systemd/system/server-audit.service
[Unit]
Description=Server audit with emailed report
[Service]
Type=oneshot
ExecStart=/usr/local/bin/server_audit_notify.sh --email ops@example.com --user alerts@example.com --pass-file /root/.server-audit-pass
# /etc/systemd/system/server-audit.timer
[Unit]
Description=Daily server audit
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now server-audit.timer
8. Remove old reports
Each run adds about ten files to /var/log/server_audit, and the script never deletes them. Add a cleanup job that fits your retention needs. The compliance page explains why some teams keep reports longer.
echo '30 6 * * * root find /var/log/server_audit -type f -mtime +90 -delete' > /etc/cron.d/server-audit-cleanup
Command-line options
| Option | Default | What it does |
|---|---|---|
-e, --email EMAIL | none, required | Address that receives the report. Separate several with commas. |
-u, --user USERNAME | none, required | SMTP username. |
--pass-file FILE | none | Read the SMTP password from the first line of FILE. FILE must not be readable by group or others. |
SMTP_PASS variable | none | SMTP password from the environment. |
-w, --pass PASSWORD | none | SMTP password on the command line. Visible in the process list; kept for older setups. |
-f, --from ADDRESS | the SMTP username | Sender address. |
-s, --smtp HOST | smtp.forwardemail.net | SMTP server hostname. |
-p, --port PORT | 465 | SMTP port. 465 and 2465 use implicit TLS; other ports use required STARTTLS. |
-l, --level LEVEL | standard | basic, standard or thorough. See audit levels. Any other value falls back to standard. |
-i, --interval HOURS | 0 | Repeat the audit every HOURS hours in a loop that never exits. |
-o, --only-on-issues | off | Email only when the audit finds Lynis warnings, failed SSH logins or a file system at 90% or more. |
-d, --report-dir DIR | /var/log/server_audit | Where report files go. |
-q, --quiet | off | Stop printing log lines to the console. They still go to the log file. |
-h, --help | Print the usage text and exit with status 0. |
When more than one password source is set, --pass wins, then --pass-file, then SMTP_PASS.
The built-in --interval loop runs in the foreground and starts a new set of report files on each pass. Cron or a systemd timer is the better choice for regular runs, because it reports failures.
Troubleshooting
| What you see | Cause and fix |
|---|---|
| "Error: ... is required" and exit status 2 | --email, --user or a password source is missing, or an option is misspelled. Run with --help. |
| "password file ... must not be readable by group or others" | Run chmod 600 on the password file. |
| "Failed to send email notification" and exit status 1 | Read the curl error in /var/log/server_audit/audit_*.log. "(67) Login denied" means a wrong username or password; "(7) Failed to connect" usually means outbound port 465 is blocked, so try --port 587. |
| "Skipped: neither ss nor netstat is installed" | Install iproute2 (for ss) or net-tools (for netstat). |
| "Source: none" under failed SSH attempts | The server has no /var/log/auth.log or /var/log/secure and no journalctl. |
No email with --only-on-issues | The audit found nothing to report. The audit log says "email skipped". |