Wenn man das Script als Code formattiert?
Hier das Installationsskript install-restart-on-connections.sh (Header mit Variablen darf man sich gern selbst anpassen):
#!/usr/bin/env bash
#
# Installiert Log-Watcher mit E-Mail-Benachrichtigung bei Service-Neustart.
#
# Verwendung:
# sudo ./install-restart-on-connections.sh
#
set -euo pipefail
# =============================================================================
# KONFIGURATION – hier anpassen
# =============================================================================
MATCH_PATTERN="reached 400 connections" # Suchmuster in journalctl / Logdatei
DAEMON_SERVICE="gromox-http.service" # systemd-Unit zum Neustart
JOURNAL_UNIT="gromox-http" # Unit-Name für journalctl -u
THRESHOLD_COUNT=2 # Mindestanzahl Treffer ("mehrfach")
WINDOW_SECONDS=60 # Zeitfenster in Sekunden
COOLDOWN_SECONDS=300 # Pause zwischen Neustarts (Sekunden)
LOG_FILE="/var/log/gromox-http.log" # Logdatei (für file-Modus + E-Mail)
LOG_SOURCE="journal" # journal | file
EMAIL_TO="admin@example.com" # Empfänger
EMAIL_SUBJECT="ALERT: Service-Neustart wegen Verbindungslimit"
EMAIL_FROM_NAME="Server Monitor" # Anzeigename des Absenders
EMAIL_FROM="monitor@example.com" # Absenderadresse
# =============================================================================
WATCHER_SCRIPT="/usr/local/bin/restart-on-connections.sh"
STATE_DIR="/var/lib/restart-on-connections"
SYSTEMD_UNIT="/etc/systemd/system/restart-on-connections.service"
INSTALL_MARKER="${STATE_DIR}/.installed-by-script"
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
echo "Bitte als root ausführen: sudo $0" >&2
exit 1
fi
if [[ "$LOG_SOURCE" != "journal" && "$LOG_SOURCE" != "file" ]]; then
echo "LOG_SOURCE muss 'journal' oder 'file' sein." >&2
exit 1
fi
if ! command -v sendmail >/dev/null 2>&1; then
echo "WARNUNG: sendmail nicht gefunden. E-Mail-Versand schlägt fehl." >&2
echo " Installiere z.B.: apt install postfix libsasl2-modules" >&2
fi
echo "==> Installiere restart-on-connections"
echo " Daemon: $DAEMON_SERVICE"
echo " Muster: $MATCH_PATTERN"
echo " Schwellwert: >= ${THRESHOLD_COUNT} in ${WINDOW_SECONDS}s"
echo " Cooldown: ${COOLDOWN_SECONDS}s"
echo " Log-Quelle: $LOG_SOURCE"
echo " E-Mail an: $EMAIL_TO"
echo
# --- Watcher-Skript erzeugen (Variablen werden hier eingebettet) ---
cat > "$WATCHER_SCRIPT" <<EOF
#!/usr/bin/env bash
set -euo pipefail
MATCH_PATTERN='${MATCH_PATTERN}'
DAEMON_SERVICE='${DAEMON_SERVICE}'
JOURNAL_UNIT='${JOURNAL_UNIT}'
THRESHOLD_COUNT=${THRESHOLD_COUNT}
WINDOW_SECONDS=${WINDOW_SECONDS}
COOLDOWN_SECONDS=${COOLDOWN_SECONDS}
LOG_FILE='${LOG_FILE}'
LOG_SOURCE='${LOG_SOURCE}'
EMAIL_TO='${EMAIL_TO}'
EMAIL_SUBJECT='${EMAIL_SUBJECT}'
EMAIL_FROM_NAME='${EMAIL_FROM_NAME}'
EMAIL_FROM='${EMAIL_FROM}'
STATE_DIR='${STATE_DIR}'
TIMESTAMP_FILE="\${STATE_DIR}/events.tsv"
COOLDOWN_FILE="\${STATE_DIR}/last_restart"
mkdir -p "\$STATE_DIR"
touch "\$TIMESTAMP_FILE"
log() {
logger -t restart-on-connections "\$*"
}
get_last_log_lines() {
local lines=""
if [[ "\$LOG_SOURCE" == "journal" ]]; then
lines=\$(journalctl -u "\$JOURNAL_UNIT" -n 10 --no-pager -o cat 2>/dev/null || true)
else
lines=\$(tail -n 10 "\$LOG_FILE" 2>/dev/null || true)
fi
if [[ -z "\$lines" ]]; then
lines="(keine Protokollzeilen verfügbar)"
fi
printf '%s' "\$lines"
}
send_restart_email() {
local log_tail="\$1"
if ! command -v sendmail >/dev/null 2>&1; then
log "sendmail nicht verfügbar – E-Mail konnte nicht gesendet werden."
return 1
fi
{
printf 'From: %s <%s>\n' "\$EMAIL_FROM_NAME" "\$EMAIL_FROM"
printf 'To: %s\n' "\$EMAIL_TO"
printf 'Subject: %s\n' "\$EMAIL_SUBJECT"
printf 'Content-Type: text/plain; charset=UTF-8\n'
printf '\n'
printf 'Der Service %s wurde automatisch neu gestartet.\n\n' "\$DAEMON_SERVICE"
printf 'Auslöser: mindestens %d Vorkommen von\n' "\$THRESHOLD_COUNT"
printf ' "%s"\n' "\$MATCH_PATTERN"
printf 'innerhalb von %d Sekunden.\n\n' "\$WINDOW_SECONDS"
printf 'Letzte 10 Protokollzeilen:\n'
printf '------------------------\n'
printf '%s\n' "\$log_tail"
printf '------------------------\n'
printf 'Zeitpunkt: %s\n' "\$(date -Iseconds)"
} | sendmail -t -oi
log "Benachrichtigungs-E-Mail an \${EMAIL_TO} gesendet."
}
prune_old_events() {
local cutoff now
now=\$(date +%s)
cutoff=\$((now - WINDOW_SECONDS))
awk -v cutoff="\$cutoff" '\$1 >= cutoff' "\$TIMESTAMP_FILE" > "\${TIMESTAMP_FILE}.tmp" \\
&& mv "\${TIMESTAMP_FILE}.tmp" "\$TIMESTAMP_FILE"
}
count_recent_events() {
wc -l < "\$TIMESTAMP_FILE" | tr -d ' '
}
in_cooldown() {
[[ -f "\$COOLDOWN_FILE" ]] || return 1
local last now
last=\$(cat "\$COOLDOWN_FILE")
now=\$(date +%s)
(( now - last < COOLDOWN_SECONDS ))
}
restart_daemon() {
local log_tail
log_tail=\$(get_last_log_lines)
log "Threshold reached (\${THRESHOLD_COUNT}+ events in \${WINDOW_SECONDS}s). Restarting \${DAEMON_SERVICE}..."
systemctl restart "\$DAEMON_SERVICE"
date +%s > "\$COOLDOWN_FILE"
: > "\$TIMESTAMP_FILE"
send_restart_email "\$log_tail"
log "Restart completed."
}
handle_line() {
local line="\$1"
[[ "\$line" == *"\$MATCH_PATTERN"* ]] || return 0
date +%s >> "\$TIMESTAMP_FILE"
prune_old_events
local count
count=\$(count_recent_events)
if (( count >= THRESHOLD_COUNT )) && ! in_cooldown; then
restart_daemon
fi
}
follow_logs() {
if [[ "\$LOG_SOURCE" == "journal" ]]; then
journalctl -u "\$JOURNAL_UNIT" -f -n 0 --no-pager 2>/dev/null | while IFS= read -r line; do
handle_line "\$line"
done
else
tail -F "\$LOG_FILE" 2>/dev/null | while IFS= read -r line; do
handle_line "\$line"
done
fi
}
check_recent_logs() {
local since
since=\$(date -d "-\${WINDOW_SECONDS} seconds" '+%F %T')
if [[ "\$LOG_SOURCE" == "journal" ]]; then
journalctl -u "\$JOURNAL_UNIT" --since "\$since" --no-pager -o cat \\
| grep -F "\$MATCH_PATTERN" || true
else
grep -F "\$MATCH_PATTERN" "\$LOG_FILE" 2>/dev/null | tail -n 100 || true
fi | while IFS= read -r line; do
handle_line "\$line"
done
}
case "\${1:-follow}" in
follow) follow_logs ;;
check) check_recent_logs ;;
*)
echo "Usage: \$0 [follow|check]" >&2
exit 1
;;
esac
EOF
chmod 755 "$WATCHER_SCRIPT"
# --- State-Verzeichnis ---
mkdir -p "$STATE_DIR"
touch "${STATE_DIR}/events.tsv"
chmod 755 "$STATE_DIR"
chmod 644 "${STATE_DIR}/events.tsv"
# --- systemd-Unit ---
cat > "$SYSTEMD_UNIT" <<EOF
[Unit]
Description=Restart daemon on repeated log pattern matches with email alert
After=network.target
[Service]
Type=simple
ExecStart=${WATCHER_SCRIPT} follow
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
chmod 644 "$SYSTEMD_UNIT"
# --- Installations-Marker ---
cat > "$INSTALL_MARKER" <<EOF
WATCHER_SCRIPT=${WATCHER_SCRIPT}
STATE_DIR=${STATE_DIR}
SYSTEMD_UNIT=${SYSTEMD_UNIT}
DAEMON_SERVICE=${DAEMON_SERVICE}
JOURNAL_UNIT=${JOURNAL_UNIT}
MATCH_PATTERN=${MATCH_PATTERN}
THRESHOLD_COUNT=${THRESHOLD_COUNT}
WINDOW_SECONDS=${WINDOW_SECONDS}
COOLDOWN_SECONDS=${COOLDOWN_SECONDS}
LOG_SOURCE=${LOG_SOURCE}
LOG_FILE=${LOG_FILE}
EMAIL_TO=${EMAIL_TO}
EMAIL_SUBJECT=${EMAIL_SUBJECT}
EMAIL_FROM=${EMAIL_FROM}
INSTALLED_AT=$(date -Iseconds)
EOF
chmod 644 "$INSTALL_MARKER"
# --- Service aktivieren ---
systemctl daemon-reload
systemctl enable restart-on-connections.service
systemctl restart restart-on-connections.service
echo
echo "==> Installation abgeschlossen."
echo " Watcher: $WATCHER_SCRIPT"
echo " Service: $SYSTEMD_UNIT"
echo " State: $STATE_DIR"
echo
systemctl --no-pager status restart-on-connections.service || true
echo
echo "Watcher-Logs: journalctl -t restart-on-connections -f"
echo "E-Mail-Test: sendmail -bv ${EMAIL_TO}"`
Ja, es gibt auch ein uninstall Skript für den Fall dass Grommunio das Problem selber hinbekommt, uninstall-restart-on-connections.sh :
#!/usr/bin/env bash
#
# Entfernt die restart-on-connections-Installation vollständig.
#
# Verwendung:
# sudo ./uninstall-restart-on-connections.sh
#
set -euo pipefail
SERVICE_NAME="restart-on-connections.service"
DEFAULT_WATCHER="/usr/local/bin/restart-on-connections.sh"
DEFAULT_STATE="/var/lib/restart-on-connections"
DEFAULT_UNIT="/etc/systemd/system/restart-on-connections.service"
INSTALL_MARKER="${DEFAULT_STATE}/.installed-by-script"
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
echo "Bitte als root ausführen: sudo $0" >&2
exit 1
fi
# Pfade aus Installations-Marker laden, falls vorhanden
WATCHER_SCRIPT="$DEFAULT_WATCHER"
STATE_DIR="$DEFAULT_STATE"
SYSTEMD_UNIT="$DEFAULT_UNIT"
if [[ -f "$INSTALL_MARKER" ]]; then
# shellcheck disable=SC1090
source "$INSTALL_MARKER"
echo "==> Installations-Marker gefunden: $INSTALL_MARKER"
else
echo "==> Kein Installations-Marker gefunden, verwende Standardpfade."
fi
echo "==> Deinstalliere restart-on-connections"
echo
# --- Service stoppen und deaktivieren ---
if systemctl list-unit-files "$SERVICE_NAME" &>/dev/null; then
if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
echo " Stoppe $SERVICE_NAME ..."
systemctl stop "$SERVICE_NAME"
fi
if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null; then
echo " Deaktiviere $SERVICE_NAME ..."
systemctl disable "$SERVICE_NAME"
fi
else
echo " Service $SERVICE_NAME nicht registriert, überspringe."
fi
# --- Dateien entfernen ---
remove_file() {
local f="$1"
if [[ -e "$f" ]]; then
echo " Lösche $f"
rm -f "$f"
fi
}
remove_dir() {
local d="$1"
if [[ -d "$d" ]]; then
echo " Lösche Verzeichnis $d"
rm -rf "$d"
fi
}
remove_file "$SYSTEMD_UNIT"
remove_file "$WATCHER_SCRIPT"
remove_dir "$STATE_DIR"
# --- systemd neu laden ---
systemctl daemon-reload
systemctl reset-failed restart-on-connections.service 2>/dev/null || true
echo
echo "==> Deinstallation abgeschlossen."
echo " Der überwachte Daemon ($DAEMON_SERVICE) wurde NICHT verändert."`
Habe es aus dem Mail genommen.