Obelica Docs
Operazioni

Monitoraggio e alert

Sistema di health check, bot Telegram interattivo e notifiche per Obelica

Overview

Il monitoraggio di Obelica ha due livelli:

  1. Health check automatico — script Bash che gira ogni 5 minuti e invia alert su Telegram.
  2. 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

PathRuolo
/opt/obelica/infra/monitoring/check-health.shhealth check automatico
/opt/obelica/infra/monitoring/send-alert.shinvio push alert
/opt/obelica/infra/monitoring/alert.envtoken e chat ID Telegram
/opt/obelica/infra/monitoring/last-monitor-statusstato precedente per deduplicazione
/opt/obelica/backups/last-backup-statusstato ultimo backup
/opt/obelica/logs/monitor.loglog health check
/opt/obelica/infra/monitoring/docker-compose.ymlservizio 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 su TELEGRAM_CHAT_ID);
  • ADMIN_CHAT_IDS — chat con privilegi admin (fallback su TELEGRAM_CHAT_ID).

Check eseguiti

  1. Disco: alert se uso >= 85% o liberi < 15 GB.
  2. Memoria: alert se RAM disponibile < 200 MB; alert se swap >= 90%.
  3. Container critici: traefik, forgejo, forgejo-db devono essere running.
  4. Servizi systemd: docker, ssh, fail2ban, ufw devono essere active.
  5. Backup: legge last-backup-status; alert su FAIL o se l'ultimo OK è più vecchio di 28 ore.
  6. Endpoint HTTPS: test.obelica.com, vps.obelica.com, tulpa-studio.vps.obelica.com.
  7. 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.sh usava jq, assente nel container del runner: ora usa POST form-encoded verso l'API Telegram (nessuna dipendenza); jq e' 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/HTML

Ogni modulo in modules/ esporta register_handlers(app). Per aggiungere una nuova sezione:

  1. creare modules/nuovo.py con register_handlers(app);
  2. importare il modulo in core/app.py e aggiungerlo alla lista MODULES.
🖥️  Stato host    📦 Container    🌐 Endpoint
📁  Progetti      💾 Backup       ⚠️  Alert
⚙️  Admin

Sezioni

  • 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: viewer legge stato/log; admin esegue 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>&1

Comandi 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-bot

Troubleshooting bot

Il bot non risponde

docker ps --filter name=obelica-bot
docker logs --tail 50 obelica-bot

Verificare 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:

  1. obelica backup run
  2. obelica backup offsite-sync
  3. obelica backup verify-offsite
  4. cleanup snapshot orfani (più vecchi dell'ultimo backup verificato)
  5. 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.sh per pulire automaticamente gli orfani prima della prune.
  • Eseguita obelica backup prune-local --keep 1 con successo.
  • Aggiornato last-backup-status a 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).

On this page