Initial VPS operations handbook

This commit is contained in:
windyboy
2026-08-03 12:26:42 +08:00
commit b73125e5bc
97 changed files with 3641 additions and 0 deletions
@@ -0,0 +1,6 @@
---
email_alert_config_path: /etc/vps-health/alert-smtp.conf
email_alert_state_path: /var/lib/vps-health/alert-state
email_alert_recipient: ''
email_alert_enabled: false
email_alert_repeat_hours: 24
@@ -0,0 +1,4 @@
---
- name: Reload systemd
ansible.builtin.systemd_service:
daemon_reload: true
+50
View File
@@ -0,0 +1,50 @@
---
# The health-check service owns the sole dispatcher hook. This role only
# installs/removes that dispatcher according to the explicit opt-in below.
- name: Require explicit non-secret alert recipient when email is enabled
ansible.builtin.assert:
that:
- email_alert_recipient | length > 0
fail_msg: Set email_alert_recipient outside version control before enabling alerts.
when: email_alert_enabled | bool
- name: Install alert integration when explicitly enabled
when: email_alert_enabled | bool
block:
- name: Install alert state directory
ansible.builtin.file:
path: "{{ email_alert_state_path | dirname }}"
state: directory
owner: root
group: root
mode: "0750"
- name: Install secret-free alert dispatcher
ansible.builtin.template:
src: alert-dispatch.sh.j2
dest: /usr/local/lib/vps-health/alert-dispatch
owner: root
group: root
mode: "0750"
- name: Remove alert integration when disabled
when: not (email_alert_enabled | bool)
block:
- name: Remove alert dispatcher
ansible.builtin.file:
path: /usr/local/lib/vps-health/alert-dispatch
state: absent
- name: Remove legacy alert service drop-in
ansible.builtin.file:
path: /etc/systemd/system/vps-healthcheck.service.d/alerting.conf
state: absent
notify: Reload systemd
- name: Report required server-side alert configuration
ansible.builtin.debug:
msg: >-
Email alerts are {{ 'enabled' if email_alert_enabled | bool else 'disabled' }}.
When enabled, the root-owned {{ email_alert_config_path }} must be provisioned
directly on the host and must contain SMTP settings and recipient; it is never
created or populated by this repository.
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Sends sanitized health results through the host's locally provisioned SMTP
# credentials. The config is intentionally excluded from Ansible/Git.
set -uo pipefail
config='{{ email_alert_config_path }}'
result='/var/lib/vps-health/latest.json'
state='{{ email_alert_state_path }}'
[[ -r "$config" && -r "$result" ]] || exit 0
# shellcheck source=/dev/null
source "$config"
: "${SMTP_URL:?missing SMTP_URL in server-side alert config}"
: "${ALERT_TO:?missing ALERT_TO in server-side alert config}"
status="$(python3 -c 'import json; print(json.load(open("'"$result"'"))["status"])')"
fingerprint="$(sha256sum "$result" | cut -d' ' -f1)"
previous="$(cat "$state" 2>/dev/null || true)"
now="$(date +%s)"
last_time="${previous%%:*}"; last_fp="${previous#*:}"
if [[ "$status" =~ ^(critical|unknown)$ ]] && [[ "$fingerprint" != "$last_fp" || $((now-${last_time:-0})) -ge {{ email_alert_repeat_hours }}*3600 ]]; then
subject="[${status}] VPS health $(hostname -f 2>/dev/null || hostname)"
curl --fail --silent --show-error --url "$SMTP_URL" --mail-rcpt "$ALERT_TO" --upload-file <(printf 'To: %s\nSubject: %s\nContent-Type: application/json\n\n%s\n' "$ALERT_TO" "$subject" "$(cat "$result")")
printf '%s:%s\n' "$now" "$fingerprint" > "$state"
elif [[ "$status" =~ ^(ok|warning)$ ]]; then
subject="[${status}] daily VPS health $(hostname -f 2>/dev/null || hostname)"
curl --fail --silent --show-error --url "$SMTP_URL" --mail-rcpt "$ALERT_TO" --upload-file <(printf 'To: %s\nSubject: %s\nContent-Type: application/json\n\n%s\n' "$ALERT_TO" "$subject" "$(cat "$result")")
fi
@@ -0,0 +1,2 @@
[Service]
ExecStartPost=/usr/local/lib/vps-health/alert-dispatch