From 6ae570795d9ecb5ca922b5f38e5a5da123dd0148 Mon Sep 17 00:00:00 2001 From: schererleander Date: Mon, 25 May 2026 01:57:31 +0200 Subject: feat(mail): add weekly HTML server report --- modules/services/mail.nix | 145 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/modules/services/mail.nix b/modules/services/mail.nix index 385d912..15010de 100644 --- a/modules/services/mail.nix +++ b/modules/services/mail.nix @@ -92,6 +92,151 @@ EOF ''; }; + systemd.services."weekly-report" = { + description = "Generate and send weekly server report"; + serviceConfig.Type = "oneshot"; + script = '' + HOSTNAME=$(${pkgs.coreutils}/bin/cat /etc/hostname) + + # 1. System Health + UPTIME=$(${pkgs.procps}/bin/uptime -p) + FAILED_SERVICES=$(${pkgs.systemd}/bin/systemctl --failed --no-legend --no-pager | ${pkgs.coreutils}/bin/head -n 5) + [ -z "$FAILED_SERVICES" ] && FAILED_SERVICES="None" + DISK_USAGE=$(${pkgs.coreutils}/bin/df -h) + + # 2. Security Overview + BANNED_ROWS=$(${pkgs.systemd}/bin/journalctl _COMM=fail2ban --since "1 week ago" --no-pager | ${pkgs.gnugrep}/bin/grep " Ban " | ${pkgs.gawk}/bin/awk '{ + # Log format: May 30 12:00:00 host fail2ban[123]: [jail] Ban IP + date = $1 " " $2 + match($0, /\[(.*)\] Ban (.*)/, m) + jail = m[1] + ip = m[2] + print "" ip "" jail "" date "" + }') + [ -z "$BANNED_ROWS" ] && BANNED_ROWS="No new bans this week." + + LOGIN_ROWS=$(${pkgs.systemd}/bin/journalctl _SYSTEMD_UNIT=sshd.service --since "1 week ago" --no-pager | ${pkgs.gnugrep}/bin/grep -E "Accepted (publickey|password)" | ${pkgs.gawk}/bin/awk '{ + # Log format: May 30 12:00:00 host sshd-session[123]: Accepted publickey for user from IP ... + date = $1 " " $2 " " substr($3, 1, 5) + user = $9 + ip = $11 + print "" user "" ip "" date "" + }') + [ -z "$LOGIN_ROWS" ] && LOGIN_ROWS="No logins recorded." + + # 3. Backup Status + parse_backups() { + ${pkgs.systemd}/bin/journalctl -u "$1" --since "1 week ago" --no-pager | ${pkgs.gawk}/bin/awk ' + /Archive name:/ { d=$1" "$2; n=$NF } + /Size \(compressed\):/ { s=$(NF-2)" "$(NF-1) } + /Duration:/ { t=$NF; if (n != "") { + if (n ~ /\.failed$/) { + printf "%s%sFAILED%s\n", n, d, t + } else { + printf "%s%s%s%s\n", n, d, s, t + } + n="" + } } + ' | ${pkgs.coreutils}/bin/tail -n 5 + } + + GIT_BACKUP_ROWS=$(parse_backups "borgbackup-job-git") + [ -z "$GIT_BACKUP_ROWS" ] && GIT_BACKUP_ROWS="No recent logs." + + NC_BACKUP_ROWS=$(parse_backups "borgbackup-job-nextcloud") + [ -z "$NC_BACKUP_ROWS" ] && NC_BACKUP_ROWS="No recent logs." + + # 4. Critical Events + ERRORS=$(${pkgs.systemd}/bin/journalctl -p 0..3 --since "1 week ago" --no-pager | ${pkgs.coreutils}/bin/head -n 20) + [ -z "$ERRORS" ] && ERRORS="No critical errors recorded." + + # Construct HTML + ( + ${pkgs.coreutils}/bin/echo "To: leander@schererleander.de" + ${pkgs.coreutils}/bin/echo "From: root@sachiel.schererleander.de" + ${pkgs.coreutils}/bin/echo "Subject: Weekly Report: $HOSTNAME" + ${pkgs.coreutils}/bin/echo "Content-Type: text/html; charset=UTF-8" + ${pkgs.coreutils}/bin/echo "" + ${pkgs.coreutils}/bin/cat < + + + + + + +

Weekly Report: $HOSTNAME

+ +

Server Health

+

Uptime: $UPTIME

+

Failed Services: $FAILED_SERVICES

+

Disk Usage:

+
$DISK_USAGE
+ +

Security Overview

+

Newly Banned IPs:

+ + + $BANNED_ROWS +
IP AddressJailDate
+ +

Successful SSH Logins:

+ + + $LOGIN_ROWS +
UserIP AddressDate
+ +

Backup Status

+

Git Repository

+ + + $GIT_BACKUP_ROWS +
ArchiveDateSizeDuration
+ +

Nextcloud Repository

+ + + $NC_BACKUP_ROWS +
ArchiveDateSizeDuration
+ +

Critical Events

+
$ERRORS
+ + +EOF + ) | /run/wrappers/bin/sendmail -f root@sachiel.schererleander.de leander@schererleander.de + ''; + }; + + systemd.timers."weekly-report" = { + description = "Timer for weekly server report"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "Mon 08:00:00"; + Persistent = true; + }; + }; + services.rspamd = { enable = true; locals."dkim_signing.conf".text = '' -- cgit v1.3.1