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.

Requirements
RequirementWhy the script needs it
Root accessIt writes to /var/log/server_audit, installs missing packages, reads system logs and searches the file system.
BashThe script uses Bash syntax such as [[ ]] and arrays.
curl and lynisIt installs either one with apt-get or yum if it is missing. On other systems, install both yourself.
ss or netstatUsed for the listening ports check. Without either, the script skips that check and says so in the report.
SSH logsIt reads /var/log/auth.log, then /var/log/secure, then the journal with journalctl -u ssh -u sshd.
An SMTP accountA 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

Command-line options
OptionDefaultWhat it does
-e, --email EMAILnone, requiredAddress that receives the report. Separate several with commas.
-u, --user USERNAMEnone, requiredSMTP username.
--pass-file FILEnoneRead the SMTP password from the first line of FILE. FILE must not be readable by group or others.
SMTP_PASS variablenoneSMTP password from the environment.
-w, --pass PASSWORDnoneSMTP password on the command line. Visible in the process list; kept for older setups.
-f, --from ADDRESSthe SMTP usernameSender address.
-s, --smtp HOSTsmtp.forwardemail.netSMTP server hostname.
-p, --port PORT465SMTP port. 465 and 2465 use implicit TLS; other ports use required STARTTLS.
-l, --level LEVELstandardbasic, standard or thorough. See audit levels. Any other value falls back to standard.
-i, --interval HOURS0Repeat the audit every HOURS hours in a loop that never exits.
-o, --only-on-issuesoffEmail 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_auditWhere report files go.
-q, --quietoffStop printing log lines to the console. They still go to the log file.
-h, --helpPrint 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

Troubleshooting
What you seeCause 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 1Read 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 attemptsThe server has no /var/log/auth.log or /var/log/secure and no journalctl.
No email with --only-on-issuesThe audit found nothing to report. The audit log says "email skipped".