Il mio homelab è cresciuto a strati: qualche Raspberry Pi sulla scrivania, un paio di mini PC e una manciata di VM su provider con tier gratuiti. A un certo punto mi sono ritrovato a valutare un servizio di monitoring SaaS che mi avrebbe portato via 5 euro al mese per controllare una decina di host. Non aveva senso, perché lo stesso lavoro lo posso fare con una Lambda e una tabella DynamoDB restando dentro il piano Always Free di AWS. Costo a regime: zero.

Qui racconto come l’ho costruito senza tirare in ballo identificativi del mio account.

L’architettura in due righe

Ogni host pubblica un evento JSON (uptime, carico, spazio disco, stato di un servizio) verso un endpoint HTTPS. L’endpoint è una funzione Lambda dietro un Function URL che valida un HMAC SHA-256 con segreto condiviso e scrive una riga su DynamoDB. Una seconda Lambda parte ogni cinque minuti tramite una regola EventBridge, legge le righe recenti e, se trova qualcosa fuori soglia, manda una notifica via webhook.

Il piano Always Free di Lambda offre 1 milione di invocazioni e 400.000 GB-secondi al mese. DynamoDB on-demand resta dentro la franchigia fino a 25 GB di storage e 200 milioni di richieste al mese. Per dieci host che pingano una volta al minuto si parla di circa 432.000 invocazioni mensili, ben dentro al tier.

Setup Lambda

Funzione Python 3.12, handler che valida HMAC e scrive su tabella. Il comando per crearla dal terminale fish del portatile:


aws lambda create-function \
  --function-name homelab-ingest \
  --runtime python3.12 \
  --handler app.handler \
  --role arn:aws:iam::ACCOUNT_ID:role/homelab-ingest-role \
  --zip-file fileb://function.zip

ACCOUNT_ID resta come placeholder. Il ruolo IAM ha solo dynamodb:PutItem sulla tabella di destinazione, niente wildcard e niente policy gestite generaliste.

Il Function URL lo configuro con auth NONE ma con HMAC obbligatorio nel body, validato dentro la funzione:


aws lambda create-function-url-config \
  --function-name homelab-ingest \
  --auth-type NONE

Setup DynamoDB

Tabella semplice, partition key host, sort key ts (timestamp epoch), modalità on-demand per non doversi preoccupare del capacity planning:


aws dynamodb create-table \
  --table-name homelab-metrics \
  --attribute-definitions AttributeName=host,AttributeType=S AttributeName=ts,AttributeType=N \
  --key-schema AttributeName=host,KeyType=HASH AttributeName=ts,KeyType=RANGE \
  --billing-mode PAY_PER_REQUEST

Per limitare i costi nel caso qualcosa vada storto, attivo un TTL a sette giorni con un attributo expire_at e abilito il TTL sulla tabella:


aws dynamodb update-time-to-live \
  --table-name homelab-metrics \
  --time-to-live-specification "Enabled=true, AttributeName=expire_at"

Allarmi e notifica

La Lambda di check parte da una regola EventBridge ogni cinque minuti, legge le righe degli ultimi dieci minuti per ogni host e confronta le soglie. Se un host non scrive da più di due intervalli, lo considero down. Per il fan-out delle notifiche uso un webhook generico verso un endpoint personale che converte il payload in un messaggio Telegram o un’email Resend. Lambda e DynamoDB restano l’unica spesa infrastrutturale, e quella spesa è esattamente zero.

Un caso reale

Una sera tardi, intorno alle 23:40, ho ricevuto la prima notifica seria dal nuovo stack. Un host di edge che da diversi mesi girava senza inghippi aveva smesso di inviare metriche. La Lambda di check, dopo dieci minuti di silenzio, ha emesso il webhook e mi è arrivato un alert sul telefono. Ho aperto la sessione SSH e ho trovato il filesystem in read-only per un errore I/O sull’SSD USB. Senza il monitor avrei scoperto il problema solo il giorno dopo, con i servizi giù da diverse ore. Il costo dell’infrastruttura di alerting quel mese è stato 0,00 dollari sul billing AWS, voce per voce.

Cosa funziona bene

Il modello pull-by-cron + push-da-host è semplicissimo da debuggare: i log della Lambda di ingest stanno in CloudWatch con retention a una settimana, e il payload è leggibile a occhio. La sicurezza la concentro sul segreto HMAC e sul ruolo IAM minimale, non devo gestire endpoint esposti senza autenticazione.

Limiti

Latenza fra evento e notifica sta sui 5-10 minuti, perché il check parte a intervalli fissi. Per scenari mission-critical non basta. Inoltre il free tier AWS può cambiare le clausole, quindi una volta l’anno controllo che il consumo effettivo resti dentro le voci Always Free, non quelle a 12 mesi.

In pratica

Questo stack lo uso come secondo livello, in parallelo a un check su uptime self-hosted in LAN. Se domani decidessi di spegnere tutto e tenere solo un servizio per sapere se il fuoco di casa è ancora vivo, è questo: leggero, isolato, indipendente dalla mia infrastruttura locale, e a costo zero finché AWS tiene fede al piano Always Free.


Immagine generata con Cloudflare Workers AI / FLUX.

Articolo originale su rpi.temporiti.net