Skip to content

Commit dbaaebf

Browse files
committed
feat: add node_exporter and disk/memory health-check alerting
Installs Prometheus node_exporter (enabled but unreachable externally -- UFW's default-deny-incoming policy blocks port 9100 same as everything else; open it yourself, scoped to your monitoring server's IP, to scrape remotely) and a disk/memory threshold check scheduled via cron. In the Ansible role the cron schedule only activates once health_check_alert_email is set, since alerting to nowhere is pointless. In quick-setup.sh it defaults to the local root mailbox via ALERT_EMAIL. Either way, actually delivering mail off-box requires a separately configured mail transport (e.g. msmtp) -- this only wires up the local script and schedule.
1 parent 88de4b1 commit dbaaebf

4 files changed

Lines changed: 79 additions & 1 deletion

File tree

ansible/group_vars/all.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,14 @@ fail2ban_enabled: true
2020
fail2ban_bantime: 1h
2121
fail2ban_findtime: 10m
2222
fail2ban_maxretry: 5
23+
24+
node_exporter_enabled: true
25+
26+
# health_check_enabled installs the disk/memory check script regardless.
27+
# The cron schedule is only added once health_check_alert_email is set --
28+
# alerts also require a mail transport (e.g. msmtp) configured on the box
29+
# to actually be delivered anywhere; this only wires up the local piece.
30+
health_check_enabled: true
31+
health_check_alert_email: ""
32+
health_check_disk_threshold: 80
33+
health_check_mem_free_threshold: 10

ansible/roles/ubuntu_minimal/tasks/main.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,45 @@
166166
- name: Set default locale
167167
ansible.builtin.command: "update-locale LANG={{ locale }}"
168168
changed_when: false
169+
170+
# node_exporter listens on 9100 but stays unreachable from the internet by
171+
# default -- the earlier "UFW default incoming policy: deny" task blocks it
172+
# same as everything else. Open 9100 yourself, restricted to your monitoring
173+
# server's IP, if you want to scrape it remotely.
174+
- name: Install Prometheus node_exporter
175+
ansible.builtin.apt:
176+
name: prometheus-node-exporter
177+
state: present
178+
when: node_exporter_enabled
179+
180+
- name: Enable and start node_exporter
181+
ansible.builtin.systemd:
182+
name: prometheus-node-exporter
183+
enabled: true
184+
state: started
185+
when: node_exporter_enabled
186+
187+
- name: Install cron and mail utilities for health-check alerts
188+
ansible.builtin.apt:
189+
name:
190+
- cron
191+
- mailutils
192+
state: present
193+
when: health_check_enabled
194+
195+
- name: Install disk/memory health-check script
196+
ansible.builtin.template:
197+
src: health-check.sh.j2
198+
dest: /usr/local/bin/health-check.sh
199+
owner: root
200+
group: root
201+
mode: "0755"
202+
when: health_check_enabled
203+
204+
- name: Schedule health-check via cron
205+
ansible.builtin.cron:
206+
name: "disk/memory health check"
207+
minute: "*/15"
208+
user: root
209+
job: /usr/local/bin/health-check.sh
210+
when: health_check_enabled and health_check_alert_email | length > 0
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
# Managed by Ansible - ubuntu_minimal role.
3+
df -h | awk 'NR>1 && $5+0 > {{ health_check_disk_threshold }} {print "DISK ALERT: " $0}' | mail -s "Disk Alert: $(hostname)" {{ health_check_alert_email }}
4+
5+
FREE=$(free | awk '/Mem/{printf "%.0f", $4/$2*100}')
6+
[ "$FREE" -lt {{ health_check_mem_free_threshold }} ] && echo "Low memory: ${FREE}% free" | mail -s "Memory Alert: $(hostname)" {{ health_check_alert_email }}

scripts/quick-setup.sh

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ apt-get update && apt-get upgrade -y
1313
apt-get autoremove -y
1414

1515
echo "--> Installing utilities (fail2ban, monitoring, tools)..."
16-
apt-get install -y ufw fail2ban unattended-upgrades htop ncdu iotop nethogs tmux git micro
16+
apt-get install -y ufw fail2ban unattended-upgrades htop ncdu iotop nethogs tmux git micro cron mailutils
1717

1818
# 1. Automate security & maintenance updates
1919
dpkg-reconfigure -f noninteractive unattended-upgrades
@@ -111,4 +111,23 @@ MaxRetentionSec=30day
111111
EOF
112112
systemctl restart systemd-journald
113113

114+
# 7. Prometheus node_exporter (optional monitoring). Stays unreachable from
115+
# the internet by default -- UFW only allows SSH, same as everything else.
116+
# Open 9100 yourself, restricted to your monitoring server's IP, to scrape it.
117+
apt-get install -y prometheus-node-exporter
118+
systemctl enable --now prometheus-node-exporter
119+
120+
# 8. Basic disk/memory health-check, mailed to ALERT_EMAIL (defaults to the
121+
# local root mailbox, readable on-box via `mail`). For alerts to leave the
122+
# server you need a real mail transport (e.g. msmtp) configured separately --
123+
# this only wires up the local script + schedule.
124+
cat << EOF > /usr/local/bin/health-check.sh
125+
#!/bin/bash
126+
df -h | awk 'NR>1 && \$5+0 > 80 {print "DISK ALERT: " \$0}' | mail -s "Disk Alert: \$(hostname)" "${ALERT_EMAIL:-root}"
127+
FREE=\$(free | awk '/Mem/{printf "%.0f", \$4/\$2*100}')
128+
[ "\$FREE" -lt 10 ] && echo "Low memory: \${FREE}% free" | mail -s "Memory Alert: \$(hostname)" "${ALERT_EMAIL:-root}"
129+
EOF
130+
chmod +x /usr/local/bin/health-check.sh
131+
echo "*/15 * * * * root /usr/local/bin/health-check.sh" > /etc/cron.d/health-check
132+
114133
echo "--> Setup complete. Keep this terminal open and test SSH in a NEW terminal before closing it."

0 commit comments

Comments
 (0)