From 4a0b031b8959d9e0e42a442ec43b1b4ad2c176fe Mon Sep 17 00:00:00 2001 From: Nicolas Cantu Date: Sun, 22 Mar 2026 23:35:43 +0100 Subject: [PATCH] Add LPLDF HTTPS watchdog systemd units for 4NK proxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Motivations:** - Alert when the LPLDF storefront HTTPS endpoint is down from the proxy **Root causes:** - N/A (monitoring gap) **Correctifs:** - N/A **Evolutions:** - watch-https-lpldf.sh: curl check, state file, syslog tag lpldf-https-watch, optional webhook/email via env file - systemd oneshot + 5-minute timer; install script via SSH/scp **Pages affectées:** - tools/proxy-https-watch-lpldf.sh - tools/proxy-https-watch-lpldf.env.example - deploy/proxy-units/lpldf-https-watch.service - deploy/proxy-units/lpldf-https-watch.timer - deploy/scripts/install-lpldf-https-watch-on-proxy.sh - deploy/README-lpldf-https-watch.md --- deploy/README-lpldf-https-watch.md | 32 ++++++ deploy/proxy-units/lpldf-https-watch.service | 8 ++ deploy/proxy-units/lpldf-https-watch.timer | 10 ++ .../install-lpldf-https-watch-on-proxy.sh | 39 ++++++++ tools/proxy-https-watch-lpldf.env.example | 11 +++ tools/proxy-https-watch-lpldf.sh | 98 +++++++++++++++++++ 6 files changed, 198 insertions(+) create mode 100644 deploy/README-lpldf-https-watch.md create mode 100644 deploy/proxy-units/lpldf-https-watch.service create mode 100644 deploy/proxy-units/lpldf-https-watch.timer create mode 100755 deploy/scripts/install-lpldf-https-watch-on-proxy.sh create mode 100644 tools/proxy-https-watch-lpldf.env.example create mode 100755 tools/proxy-https-watch-lpldf.sh diff --git a/deploy/README-lpldf-https-watch.md b/deploy/README-lpldf-https-watch.md new file mode 100644 index 0000000..25b17d1 --- /dev/null +++ b/deploy/README-lpldf-https-watch.md @@ -0,0 +1,32 @@ +# LPLDF HTTPS watchdog on the 4NK proxy + +## Purpose + +Detect downtime of `https://xn--lespetitesleonsdefrdric-89b1db.fr/` from the proxy and emit alerts (syslog tag `lpldf-https-watch`, optional webhooks / mail). Acts as an availability watchdog; a SIEM (e.g. Wazuh) can ingest these syslog lines. + +## Repository paths + +- Watch script (installed to `/opt/proxy-config/scripts/watch-https-lpldf.sh`): `tools/proxy-https-watch-lpldf.sh` +- Optional env example: `tools/proxy-https-watch-lpldf.env.example` +- Systemd units: `deploy/proxy-units/lpldf-https-watch.service`, `deploy/proxy-units/lpldf-https-watch.timer` +- Installer (from ia_dev root): `./deploy/scripts/install-lpldf-https-watch-on-proxy.sh` + +## Behaviour + +- Accepts HTTP status 200, 301, 302, 307, 308. +- State under `/var/lib/lpldf-https-watch/`. +- First DOWN: `daemon.warning` + optional `ALERT_WEBHOOK_URL` / `ALERT_EMAIL_TO`. +- Repeats while down at most every `ALERT_REPEAT_SECONDS` (default 3600). +- Recovery: `daemon.info` + optional `ALERT_WEBHOOK_URL_RECOVER`. + +## Optional proxy config + +Create `/opt/proxy-config/scripts/env/watch-https-lpldf.env` (e.g. `chmod 600`), see `tools/proxy-https-watch-lpldf.env.example`. + +## Operations + +- Manual run on proxy: `sudo /opt/proxy-config/scripts/watch-https-lpldf.sh` +- Logs: `sudo journalctl -t lpldf-https-watch` +- Timer: `systemctl status lpldf-https-watch.timer` + +Nginx is not modified for this check. diff --git a/deploy/proxy-units/lpldf-https-watch.service b/deploy/proxy-units/lpldf-https-watch.service new file mode 100644 index 0000000..ce48cc9 --- /dev/null +++ b/deploy/proxy-units/lpldf-https-watch.service @@ -0,0 +1,8 @@ +[Unit] +Description=HTTPS availability check for LPLDF (Les Petites Lecons) +After=network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +ExecStart=/opt/proxy-config/scripts/watch-https-lpldf.sh diff --git a/deploy/proxy-units/lpldf-https-watch.timer b/deploy/proxy-units/lpldf-https-watch.timer new file mode 100644 index 0000000..f611722 --- /dev/null +++ b/deploy/proxy-units/lpldf-https-watch.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Run LPLDF HTTPS watch every 5 minutes + +[Timer] +OnBootSec=3min +OnUnitActiveSec=5min +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/deploy/scripts/install-lpldf-https-watch-on-proxy.sh b/deploy/scripts/install-lpldf-https-watch-on-proxy.sh new file mode 100755 index 0000000..a8333ea --- /dev/null +++ b/deploy/scripts/install-lpldf-https-watch-on-proxy.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Install HTTPS watchdog + systemd timer on the 4NK proxy (192.168.1.100). +# Does not modify Nginx. Run from ia_dev root: ./deploy/scripts/install-lpldf-https-watch-on-proxy.sh +set -euo pipefail + +IA_DEV_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# shellcheck source=deploy/_lib/ssh.sh +source "${IA_DEV_ROOT}/deploy/_lib/ssh.sh" + +readonly SSH_KEY="${DEPLOY_SSH_KEY:-${HOME}/.ssh/id_ed25519}" +readonly SSH_USER="${DEPLOY_SSH_USER:-ncantu}" +readonly PROXY_HOST="${DEPLOY_PROXY_HOST:-192.168.1.100}" +export DEPLOY_SSH_PROXY_HOST="${DEPLOY_SSH_PROXY_HOST:-4nk.myftp.biz}" + +readonly REMOTE_SCRIPT="/opt/proxy-config/scripts/watch-https-lpldf.sh" +readonly REMOTE_ENV_DIR="/opt/proxy-config/scripts/env" +readonly REMOTE_ENV="${REMOTE_ENV_DIR}/watch-https-lpldf.env" +readonly SERVICE_NAME="lpldf-https-watch" + +scp_copy "$SSH_KEY" "${IA_DEV_ROOT}/tools/proxy-https-watch-lpldf.sh" "$SSH_USER" "$PROXY_HOST" "/tmp/watch-https-lpldf.sh" "false" +scp_copy "$SSH_KEY" "${IA_DEV_ROOT}/deploy/proxy-units/${SERVICE_NAME}.service" "$SSH_USER" "$PROXY_HOST" "/tmp/${SERVICE_NAME}.service" "false" +scp_copy "$SSH_KEY" "${IA_DEV_ROOT}/deploy/proxy-units/${SERVICE_NAME}.timer" "$SSH_USER" "$PROXY_HOST" "/tmp/${SERVICE_NAME}.timer" "false" + +ssh_run "$SSH_KEY" "$SSH_USER" "$PROXY_HOST" \ + "sudo install -d -m 755 /opt/proxy-config/scripts && \ + sudo install -d -m 700 ${REMOTE_ENV_DIR} && \ + sudo install -m 755 /tmp/watch-https-lpldf.sh ${REMOTE_SCRIPT} && \ + sudo rm -f /tmp/watch-https-lpldf.sh && \ + sudo install -d -m 755 /var/lib/lpldf-https-watch && \ + sudo install -m 644 /tmp/${SERVICE_NAME}.service /etc/systemd/system/${SERVICE_NAME}.service && \ + sudo install -m 644 /tmp/${SERVICE_NAME}.timer /etc/systemd/system/${SERVICE_NAME}.timer && \ + sudo rm -f /tmp/${SERVICE_NAME}.service /tmp/${SERVICE_NAME}.timer && \ + sudo systemctl daemon-reload && \ + sudo systemctl enable --now ${SERVICE_NAME}.timer && \ + sudo systemctl start ${SERVICE_NAME}.service || true && \ + systemctl --no-pager --full status ${SERVICE_NAME}.timer" + +echo "[install-lpldf-https-watch] Installed ${REMOTE_SCRIPT} and ${SERVICE_NAME}.timer on ${PROXY_HOST}" +echo "[install-lpldf-https-watch] Optional: create ${REMOTE_ENV} (chmod 600); see tools/proxy-https-watch-lpldf.env.example" diff --git a/tools/proxy-https-watch-lpldf.env.example b/tools/proxy-https-watch-lpldf.env.example new file mode 100644 index 0000000..c3df7fd --- /dev/null +++ b/tools/proxy-https-watch-lpldf.env.example @@ -0,0 +1,11 @@ +# Copy to /opt/proxy-config/scripts/env/watch-https-lpldf.env on the proxy (chmod 600). +# Optional: webhook for down alerts (plain text POST body). +# ALERT_WEBHOOK_URL=https://example.com/hook +# Optional: separate webhook when the site recovers. +# ALERT_WEBHOOK_URL_RECOVER=https://example.com/hook-recover +# Optional: repeat down notifications at most every N seconds while still failing. +# ALERT_REPEAT_SECONDS=3600 +# Optional: if `mail` is configured on the host. +# ALERT_EMAIL_TO=ops@example.com +# Override URL if needed (default is punycode LPLDF front URL). +# WATCH_URL=https://xn--lespetitesleonsdefrdric-89b1db.fr/ diff --git a/tools/proxy-https-watch-lpldf.sh b/tools/proxy-https-watch-lpldf.sh new file mode 100755 index 0000000..8508fa6 --- /dev/null +++ b/tools/proxy-https-watch-lpldf.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash +# HTTPS availability watchdog for Les Petites Leçons de Frédéric (punycode host). +# Intended path on proxy: /opt/proxy-config/scripts/watch-https-lpldf.sh +# Optional env file (root-only recommended): /opt/proxy-config/scripts/env/watch-https-lpldf.env +# Syslog identifier: lpldf-https-watch (for SIEM / Wazuh-style log collection). +set -euo pipefail + +readonly WATCH_URL="${WATCH_URL:-https://xn--lespetitesleonsdefrdric-89b1db.fr/}" +readonly STATE_DIR="${STATE_DIR:-/var/lib/lpldf-https-watch}" +readonly STATE_FILE="${STATE_DIR}/last_state" +readonly LAST_ALERT_FILE="${STATE_DIR}/last_alert_epoch" +readonly LOG_TAG="lpldf-https-watch" + +ENV_FILE="${ENV_FILE:-/opt/proxy-config/scripts/env/watch-https-lpldf.env}" +if [[ -f "$ENV_FILE" ]]; then + set -a + # shellcheck disable=SC1090 + source "$ENV_FILE" + set +a +fi + +readonly ALERT_REPEAT_SECONDS="${ALERT_REPEAT_SECONDS:-3600}" + +mkdir -p "$STATE_DIR" + +last="OK" +if [[ -f "$STATE_FILE" ]]; then + last="$(tr -d '\n' <"$STATE_FILE" || true)" +fi +[[ -z "$last" ]] && last="OK" + +http_code="000" +if ! http_code="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 25 "$WATCH_URL" 2>/dev/null)"; then + http_code="000" +fi +[[ -z "$http_code" ]] && http_code="000" + +is_ok="false" +if [[ "$http_code" =~ ^(200|301|302|307|308)$ ]]; then + is_ok="true" +fi + +send_notifications() { + local message="$1" + logger -t "$LOG_TAG" -p daemon.warning "$message" + if [[ -n "${ALERT_WEBHOOK_URL:-}" ]]; then + curl -sS -X POST "${ALERT_WEBHOOK_URL}" \ + -H "Content-Type: text/plain; charset=utf-8" \ + --data-binary "$message" \ + --max-time 15 || logger -t "$LOG_TAG" -p daemon.err "ALERT_WEBHOOK_URL post failed" + fi + if [[ -n "${ALERT_EMAIL_TO:-}" ]] && command -v mail >/dev/null 2>&1; then + printf '%s\n' "$message" | mail -s "LPLDF HTTPS down" "$ALERT_EMAIL_TO" || logger -t "$LOG_TAG" -p daemon.err "mail alert failed" + fi +} + +notify_recovery() { + local message="$1" + logger -t "$LOG_TAG" -p daemon.info "$message" + if [[ -n "${ALERT_WEBHOOK_URL_RECOVER:-}" ]]; then + curl -sS -X POST "${ALERT_WEBHOOK_URL_RECOVER}" \ + -H "Content-Type: text/plain; charset=utf-8" \ + --data-binary "$message" \ + --max-time 15 || true + fi +} + +now_epoch="$(date +%s)" + +if [[ "$is_ok" == "true" ]]; then + if [[ "$last" == "DOWN" ]]; then + notify_recovery "LPLDF HTTPS recovered: ${WATCH_URL} HTTP ${http_code}" + fi + printf '%s\n' "OK" >"$STATE_FILE" + exit 0 +fi + +msg="LPLDF HTTPS check FAIL: ${WATCH_URL} HTTP=${http_code}" + +if [[ "$last" != "DOWN" ]]; then + printf '%s\n' "DOWN" >"$STATE_FILE" + printf '%s\n' "$now_epoch" >"$LAST_ALERT_FILE" + send_notifications "$msg" + exit 1 +fi + +last_alert="0" +if [[ -f "$LAST_ALERT_FILE" ]]; then + last_alert="$(tr -d '\n' <"$LAST_ALERT_FILE" || echo 0)" +fi +[[ -z "$last_alert" ]] && last_alert="0" + +if [[ "$((now_epoch - last_alert))" -ge "$ALERT_REPEAT_SECONDS" ]]; then + printf '%s\n' "$now_epoch" >"$LAST_ALERT_FILE" + send_notifications "$msg (still down, repeat every ${ALERT_REPEAT_SECONDS}s)" +fi + +exit 1