Monitoraggio e alert
Sistema di health check, bot Telegram interattivo e notifiche per Obelica
Overview
Il monitoraggio di Obelica ha due livelli:
- Health check automatico — script Bash che gira ogni 5 minuti e invia alert su Telegram.
- Bot Telegram interattivo — bot Python con menu navigabile per consultare lo stato dell'host, dei container, dei progetti, del backup e degli alert on-demand.
Componenti
| Path | Ruolo |
|---|---|
/opt/obelica/infra/monitoring/check-health.sh | health check automatico |
/opt/obelica/infra/monitoring/send-alert.sh | invio push alert |
/opt/obelica/infra/monitoring/alert.env | token e chat ID Telegram |
/opt/obelica/infra/monitoring/last-monitor-status | stato precedente per deduplicazione |
/opt/obelica/backups/last-backup-status | stato ultimo backup |
/opt/obelica/logs/monitor.log | log health check |
/opt/obelica/infra/monitoring/docker-compose.yml | servizio obelica-bot |
/opt/obelica/infra/monitoring/bot/ | codice sorgente del bot |
/opt/obelica/infra/monitoring/bot-data/ | SQLite audit log e storico alert |
Configurazione alert
/opt/obelica/infra/monitoring/alert.env:
ALERT_PROVIDER=telegram
TELEGRAM_BOT_TOKEN=<redacted>
TELEGRAM_CHAT_ID=<redacted>Permessi: 600.
Il bot legge lo stesso file e riconosce anche:
ALLOWED_CHAT_IDS— chat autorizzate (fallback suTELEGRAM_CHAT_ID);ADMIN_CHAT_IDS— chat con privilegi admin (fallback suTELEGRAM_CHAT_ID).
Check eseguiti
- Disco: alert se uso >= 85% o liberi < 15 GB.
- Memoria: alert se RAM disponibile < 200 MB; alert se swap >= 90%.
- Container critici:
traefik,forgejo,forgejo-dbdevono essere running. - Servizi systemd:
docker,ssh,fail2ban,ufwdevono essere active. - Backup: legge
last-backup-status; alert su FAIL o se l'ultimo OK è più vecchio di 28 ore. - Endpoint HTTPS:
test.obelica.com,vps.obelica.com,tulpa-studio.vps.obelica.com. - TLS: alert se in scadenza entro 14 giorni.
Deduplicazione alert
Gli alert vengono inviati solo su cambio stato o cambio insieme di problemi. Quando lo stato torna OK, arriva un messaggio di recovery.
Alert sui deploy falliti (dal 2026-07-03)
Ogni workflow deploy.yml (13 repo + template infra/templates/app-deploy.yml)
ha uno step if: failure() che chiama send-alert.sh: un deploy rosso ora
genera un messaggio Telegram invece di restare visibile solo nei log del
runner. Verificato end-to-end con un deploy fallito controllato
(workflow_dispatch su repo dirty → guardia del deploy → alert ricevuto).
Due insidie risolte durante il rollout, da ricordare:
- il messaggio dello step conteneva
:che in uno scalare YAML non quotato apre un mapping → run falliti a livello parse (e i fallimenti di parse NON eseguono step, quindi restano senza alert). La run line va tenuta come scalare single-quoted; send-alert.shusavajq, assente nel container del runner: ora usa POST form-encoded verso l'API Telegram (nessuna dipendenza);jqe' stato comunque aggiunto al Dockerfile del runner per la prossima rebuild.
Limite noto: i fallimenti di parse del workflow (YAML rotto) non producono
alert — solo lo stato rosso in Forgejo. Un check periodico su action_run
resta un miglioramento futuro (candidato per il cron contract).
Fix log duplicati (2026-07-03)
check-health.sh e backup-cron-wrapper.sh usavano tee -a sul log mentre
il crontab redirigeva stdout sullo stesso file: ogni riga risultava doppia.
Ora log() scrive su file direttamente quando stdout non e' una TTY
(backup dei file in *.bak-20260703). Verificato: 1 riga per check.
Bot Telegram interattivo
Bot scritto in Python con python-telegram-bot, eseguito come container Docker in modalità polling.
Architettura modulare
bot/
├── main.py # entry point e CLI
├── config.py # configurazione
├── core/
│ ├── app.py # application PTB + auto-registrazione moduli
│ ├── renderer.py # rendering messaggi HTML
│ ├── security.py # autorizzazioni e audit
│ └── menu.py # menu principale
├── modules/ # una cartella per ogni sezione
│ ├── start.py
│ ├── host.py
│ ├── containers.py
│ ├── projects.py
│ ├── endpoints.py
│ ├── backup.py
│ ├── alerts.py
│ └── admin.py
├── services/ # logica di interrogazione sistema/Docker
├── storage/ # SQLite
└── utils/ # helpers testuali/HTMLOgni modulo in modules/ esporta register_handlers(app). Per aggiungere una nuova sezione:
- creare
modules/nuovo.pyconregister_handlers(app); - importare il modulo in
core/app.pye aggiungerlo alla listaMODULES.
Menu principale
🖥️ Stato host 📦 Container 🌐 Endpoint
📁 Progetti 💾 Backup ⚠️ Alert
⚙️ AdminSezioni
- Stato host: uptime, load, CPU, RAM, swap, disco, top processi.
- Container: lista paginata, dettaglio con risorse, log, restart/start/stop.
- Progetti: progetti ricavati da
/opt/obelica/repos/*e/opt/obelica/apps/*; per ogni progetto vengono mostrati i container associati, gli endpoint HTTPS letti dalle label Traefik e lo stato. - Endpoint: stato HTTPS degli endpoint noti e giorni rimanenti certificato TLS.
- Backup: stato ultimo backup, età, lista backup locali; azioni admin per avviare backup e verifica offsite.
- Alert recenti: storico alert, test alert, silenzia/riattiva per chat.
- Admin: chat autorizzate, audit log, reload configurazione.
Comandi slash
/start— menu principale/help— comandi e ruolo/status— stato host/containers— lista container/logs <container> [n]— log/restart <container>— restart (admin)/backup— stato backup/projects— lista progetti/project <nome>— dettaglio progetto/alerttest— test alert
Sicurezza
- Whitelist: solo chat in
ALLOWED_CHAT_IDS. - Ruoli:
viewerlegge stato/log;adminesegue azioni. - Audit log: ogni azione in SQLite.
- Input sanitizzato: nomi validati, comandi con timeout, HTML escapato per i valori dinamici.
- Docker socket: montato read-only; container non-root (
obelica, UID 1000).
Storico alert
check-health.sh chiama il bot dopo ogni alert:
docker exec obelica-bot python main.py record-alert --status "$current_status" --message "$message"I messaggi vengono salvati in SQLite e mostrati nella sezione Alert.
Cron
0 4 * * * /opt/obelica/infra/scripts/backup-cron-wrapper.sh >> /opt/obelica/backups/backup-cron.log 2>&1
*/5 * * * * /opt/obelica/infra/monitoring/check-health.sh >> /opt/obelica/logs/monitor.log 2>&1Comandi utili
# Health check manuale
/opt/obelica/infra/monitoring/check-health.sh
# Test alert push
/opt/obelica/infra/monitoring/send-alert.sh "Messaggio di test"
# Test dal bot
sudo docker exec obelica-bot python main.py send-test
# Registra alert nel bot
sudo docker exec obelica-bot python main.py record-alert --status FAIL --message "Prova"
# Stato monitoraggio e backup
cat /opt/obelica/infra/monitoring/last-monitor-status
cat /opt/obelica/backups/last-backup-status
# Log
tail -f /opt/obelica/logs/monitor.log
docker logs -f obelica-bot
# Rebuild bot
cd /opt/obelica/infra/monitoring && docker compose up -d --build obelica-botTroubleshooting bot
Il bot non risponde
docker ps --filter name=obelica-bot
docker logs --tail 50 obelica-botVerificare che TELEGRAM_BOT_TOKEN sia valido e che la chat sia autorizzata.
Il bot non vede i container
Il container obelica-bot deve accedere a /var/run/docker.sock. Il GID del gruppo docker host è 987 ed è configurato in docker-compose.yml tramite group_add. Se cambia, aggiornare il valore.
Tag HTML visibili
I messaggi passano tutti da core.renderer con parse_mode="HTML". Se compaiono tag visibili, segnalarlo: probabilmente un modulo usa edit_message_text senza passare dal renderer.
Pipeline backup
Il backup automatico è orchestrato da /opt/obelica/infra/scripts/backup-cron-wrapper.sh:
obelica backup runobelica backup offsite-syncobelica backup verify-offsite- cleanup snapshot orfani (più vecchi dell'ultimo backup verificato)
obelica backup prune-local --keep 1
Se uno snapshot locale non ha il manifest offsite ed è più vecchio dell'ultimo backup verificato, viene rimosso automaticamente prima della prune. Questo evita che snapshot residui di run interrotti o manuali blocchino la pipeline.
Fix backup — snapshot orfano (28 giugno 2026)
Il backup segnalava FAIL: local prune failed perché esisteva uno snapshot locale 20260626-161111 privo di manifest offsite. Lo snapshot bloccava la prune per precauzione.
Interventi:
- Rimosso manualmente lo snapshot orfano.
- Modificato
backup-cron-wrapper.shper pulire automaticamente gli orfani prima della prune. - Eseguita
obelica backup prune-local --keep 1con successo. - Aggiornato
last-backup-statusa OK.
Stato attuale: backup OK, rimane solo lo snapshot più recente (20260628-040001) in locale, con copia offsite verificata.
Gap futuri
- Heartbeat giornaliero quando tutto è OK.
- Metriche storiche (Prometheus/Grafana).
- Canali alert multipli (email/webhook).