Perché un bot Telegram?
Quando gestisci un server in produzione, la cosa peggiore è scoprire che qualcosa è andato storto ore dopo che è successo. Email di alert? Finiscono nello spam. PagerDuty? Overkill per un progetto personale. Un bot Telegram invece è gratuito, arriva sul telefono in tempo reale e si configura in 10 minuti.
In questo articolo costruiamo un sistema che:
- Monitora
error_logdi PHP e ti notifica i nuovi errori - Controlla che i tuoi servizi (HTTP, porte TCP) siano raggiungibili
- Gira come cron o servizio systemd
- È completamente in bash, zero dipendenze extra
1. Creare il bot su Telegram
Prima di tutto crea il bot tramite @BotFather:
- Apri Telegram e cerca
@BotFather - Manda
/newbot - Scegli un nome e un username (es.
miosito_monitor_bot) - Salva il token API che ti restituisce, tipo:
7123456789:AAHxxx...
Poi ottieni il tuo chat_id: manda un messaggio al bot e visita:
https://api.telegram.org/bot<TOKEN>/getUpdates
Nel JSON risposta trovi "chat":{"id":123456789} — quel numero è il tuo chat_id.
2. La funzione di invio messaggio
Creiamo il file base /usr/local/bin/tg-notify.sh:
#!/bin/bash
TG_TOKEN="7123456789:AAHxxx..."
TG_CHAT_ID="123456789"
tg_send() {
local message="$1"
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
-d chat_id="${TG_CHAT_ID}" \
-d parse_mode="HTML" \
-d text="${message}" \
> /dev/null
}
Usiamo parse_mode=HTML così possiamo formattare i messaggi con <b>, <code> ecc.
3. Monitor dell'error log PHP
Il trick è usare tail -Fn0 per seguire il file e rilevare solo le nuove righe dall'avvio del monitor:
#!/bin/bash
source /usr/local/bin/tg-notify.sh
PHP_LOG="/var/log/php/error.log"
HOSTNAME=$(hostname)
monitor_php_log() {
tail -Fn0 "$PHP_LOG" | while read -r line; do
# Filtra solo righe con errori reali (ignora notice/deprecated in dev)
if echo "$line" | grep -qiE "(Fatal error|Parse error|Warning|Uncaught)"; then
tg_send "🔴 <b>PHP Error — ${HOSTNAME}</b>
<code>${line}</code>"
fi
done
}
monitor_php_log
Tip: Se vuoi evitare flood di notifiche, aggiungi un rate limit: salva l'ultimo timestamp di invio e skippa se sono passati meno di 60 secondi per lo stesso tipo di errore.
4. Monitor dei servizi HTTP e porte TCP
#!/bin/bash
source /usr/local/bin/tg-notify.sh
HOSTNAME=$(hostname)
STATE_DIR="/tmp/tg-monitor-state"
mkdir -p "$STATE_DIR"
check_http() {
local name="$1"
local url="$2"
local state_file="${STATE_DIR}/http_${name}"
local code
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url")
if [ "$code" -lt 200 ] || [ "$code" -ge 400 ]; then
# Invia alert solo se non era già down (evita spam)
if [ ! -f "$state_file" ]; then
touch "$state_file"
tg_send "🔴 <b>DOWN: ${name}</b>
Host: <code>${HOSTNAME}</code>
URL: <code>${url}</code>
HTTP: <code>${code}</code>"
fi
else
# Era down, ora è tornato su
if [ -f "$state_file" ]; then
rm -f "$state_file"
tg_send "✅ <b>RECOVERED: ${name}</b>
Host: <code>${HOSTNAME}</code>
URL: <code>${url}</code>"
fi
fi
}
check_tcp() {
local name="$1"
local host="$2"
local port="$3"
local state_file="${STATE_DIR}/tcp_${name}"
if ! nc -z -w5 "$host" "$port" 2>/dev/null; then
if [ ! -f "$state_file" ]; then
touch "$state_file"
tg_send "🔴 <b>DOWN: ${name}</b>
Host: <code>${host}:${port}</code>"
fi
else
if [ -f "$state_file" ]; then
rm -f "$state_file"
tg_send "✅ <b>RECOVERED: ${name}</b>
Host: <code>${host}:${port}</code>"
fi
fi
}
# ── Configura qui i tuoi servizi ─────────────────────────────
check_http "sito principale" "https://donatodelpeschio.it"
check_http "api" "https://api.donatodelpeschio.it/health"
check_tcp "PostgreSQL" "localhost" "5432"
check_tcp "Redis" "localhost" "6379"
Il sistema dei state file in /tmp/tg-monitor-state/ è fondamentale: evita che tu riceva 50 notifiche "DOWN" ogni minuto per lo stesso servizio. Ricevi un alert quando cade e uno quando torna su.
5. Orchestrare tutto con systemd (meglio del cron)
Per il monitor del log PHP, il cron non va bene perché usa tail -f. Usiamo systemd:
# /etc/systemd/system/php-log-monitor.service
[Unit]
Description=PHP Error Log Telegram Monitor
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/php-log-monitor.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
systemctl enable --now php-log-monitor
Per il monitor dei servizi HTTP/TCP invece il cron è perfetto (ogni minuto):
# crontab -e
* * * * * /usr/local/bin/service-monitor.sh
6. Bonus: report giornaliero
Ogni mattina alle 9:00 ricevi un riepilogo dello stato dei servizi:
#!/bin/bash
source /usr/local/bin/tg-notify.sh
UPTIME=$(uptime -p)
DISK=$(df -h / | awk 'NR==2 {print $3"/"$2" ("$5")"}')
MEM=$(free -h | awk 'NR==2 {print $3"/"$2}')
LOAD=$(uptime | awk -F'load average:' '{print $2}')
tg_send "📊 <b>Daily Report</b>
🖥 <code>$(hostname)</code>
⏱ Uptime: <code>${UPTIME}</code>
💾 Disk: <code>${DISK}</code>
🧠 RAM: <code>${MEM}</code>
⚡ Load: <code>${LOAD}</code>"
# crontab
0 9 * * * /usr/local/bin/daily-report.sh
Risultato finale
Con meno di 100 righe di bash hai un sistema di monitoring che:
- Ti avvisa istantaneamente degli errori PHP critici
- Monitora tutti i tuoi servizi ogni minuto
- Non ti spamma (grazie agli state file)
- Ti manda un buongiorno con lo stato del server
Il prossimo step? Aggiungere un comando /status al bot per interrogare lo stato dei servizi on-demand. Ma questo è materiale per un altro articolo. 🚀