Author: fabio

  • Ridurre i costi cloud usando i free-tier

    Ridurre i costi cloud usando i free-tier

    Per chi gestisce un homelab e ogni tanto vuole appoggiare qualcosa “in cloud” (un backup off-site, una landing page, un endpoint sempre raggiungibile), i tier gratuiti dei big cloud sono un’opportunità enorme che spesso resta non sfruttata. La curva di apprendimento iniziale è fastidiosa, ma una volta capita la mappa si possono mettere in produzione cose serie con costo annuale zero.

    Riassumo come uso oggi i principali tier gratuiti, senza esporre numeri di account o tenant miei.

    Oracle Cloud Infrastructure Always Free

    Il più generoso dei tier “always free” attualmente in giro: 4 OCPU ARM Ampere A1 + 24 GB RAM da spalmare su una o più VM, 200 GB di block storage, 10 GB di object storage standard + 10 GB archive, un Autonomous Database da 20 GB. “Always free” vuol dire che non scade dopo 12 mesi (a differenza del free tier AWS che è tempo-limitato).

    Per creare una VM A1 ARM via CLI, una volta configurato oci-cli:

    
    oci compute instance launch \
      --availability-domain AD-1 \
      --compartment-id COMPARTMENT_OCID \
      --shape VM.Standard.A1.Flex \
      --shape-config '{"ocpus": 2, "memoryInGBs": 12}' \
      --image-id IMAGE_OCID \
      --subnet-id SUBNET_OCID \
      --display-name homelab-aux
    

    COMPARTMENT_OCID è nel formato ocid1.compartment.oc1.. seguito da identificativo. Lo recupero con oci iam compartment list, così come IMAGE_OCID e SUBNET_OCID. Mai metterli in chiaro su repository pubblici.

    Cosa ci faccio sopra: una VM ARM piccola che fa da bastion SSH off-site verso il mio homelab via Tailscale, e ospita servizi che voglio sempre raggiungibili anche quando casa va giù (DNS secondario, status page). Un’altra VM A1 ospita una replica InfluxDB di sola lettura come backup metriche.

    AWS Free Tier

    Il free tier AWS Always Free include 1 milione di invocazioni Lambda e 400.000 GB-secondi al mese, 25 GB DynamoDB, 1 milione di richieste DynamoDB e 100 GB di egress CloudFront. Il free a 12 mesi aggiunge 750 ore EC2 t2.micro (che scadono), 5 GB S3, 750 ore RDS.

    Per un homelab si vive bene con il solo “always free”: Lambda + DynamoDB + S3 (qui si paga storage > 5 GB anche always, ma centesimi). Esempio di upload backup su bucket con storage class IA:

    
    aws s3 mb s3://mio-backup-offsite-ACCOUNT_ID --region eu-west-1
    aws s3 cp /var/backups/db.sql.gz s3://mio-backup-offsite-ACCOUNT_ID/ \
      --storage-class STANDARD_IA
    

    STANDARD_IA costa metà di STANDARD per oggetti che non leggo spesso, con il vincolo di mantenere il file almeno 30 giorni in classe IA.

    Google Cloud Platform Free Tier

    GCP offre un free tier “always free” più modesto ma utile: una e2-micro in us-west1/us-central1/us-east1, 30 GB HDD, 5 GB Cloud Storage standard, 1 GB egress fuori dal Nord America. L’e2-micro non basta per molto, ma per un ping checker o un piccolo cron job sì.

    Cloudflare Workers e R2

    Cloudflare ha un free tier dei più pratici per un homelab. 100.000 richieste Workers al giorno, 10 GB R2 storage, 1 milione classe A operations e 10 milioni classe B operations al mese. Niente egress per R2 (è il vero killer feature rispetto a S3).

    Esempio di Worker minimale che risponde a un health check:

    
    npm create cloudflare@latest -- mio-health-worker
    cd mio-health-worker
    wrangler deploy
    

    Lo uso per pingare i miei servizi homelab via Tailscale subnet router e scriverne lo stato su KV. Il worker risponde in 30-80 ms da edge, e ho un endpoint pubblico per status page senza esporre infrastruttura mia.

    Un caso reale

    Un paio di mesi fa pagavo 7 euro al mese per una piccola VPS che ospitava un endpoint HTTPS per ricevere webhook di terze parti. Ho passato un pomeriggio a riscriverlo come Worker Cloudflare con storage su KV e ho dismesso la VPS. Conto annuale: -84 euro. Latenza del nuovo endpoint dimezzata (rispetto al VPS in singola region) e affidabilità superiore (Cloudflare edge globale). Il deploy del worker, comprese le variabili di ambiente, sta in venti righe di wrangler.toml e un singolo file index.ts. Il TCO totale di quel servizio è passato da 84 euro a 0,00 euro l’anno.

    Cosa funziona bene

    Ogni cloud ha tier complementari: OCI ti dà compute ARM serio (per VM Linux che girano 24/7), AWS ti dà serverless (Lambda+DynamoDB), GCP ti dà micro-istanze e BigQuery free, Cloudflare ti dà edge globale e storage senza egress. Mischiandoli, copri quasi ogni esigenza tipica di un homelab senza pagare.

    Limiti

    I tier gratuiti cambiano. AWS ha già rimodulato il suo free tier in passato, OCI ha avuto problemi di disponibilità ARM in certe region. Il vendor lock-in è reale anche su free: una Lambda non si sposta facilmente su Workers. Inoltre, oltre certi consumi le fatture esistono e possono fare male: configuro sempre alerting di billing a 1 euro/giorno per ogni account, e budget hard a zero dove possibile.

    In pratica

    Free tier cloud è una leva tecnica preziosa per chi gestisce un homelab. Permette di avere componenti in cloud sempre acceso (DNS secondario, status page, backup off-site, webhook endpoint) senza spese ricorrenti. La gestione costa un po’ di tempo iniziale, ma una volta scritto il setup come Infrastructure-as-Code (Terraform o equivalente), replicare è banale. E quando un servizio cresce oltre il free tier, si decide a ragion veduta se mantenerlo in cloud o portarlo sull’hardware di casa.


    Immagine generata con Cloudflare Workers AI / FLUX.

  • Disaster Recovery per il mio Homelab

    Disaster Recovery per il mio Homelab

    Disaster Recovery suona come una di quelle parole che gli enterprise usano per fare bei diagrammi. In un homelab significa una cosa molto più pragmatica: se domani brucia il modem, sparisce il NAS, mi rubano il portatile, in quanto tempo posso ricostruire e quanto ho perso? Per me la risposta deve essere: poche ore di lavoro, al massimo una settimana di dati.

    Qui descrivo come ho messo in piedi un piano DR per il mio piccolo homelab, costo annuale qualche euro, recupero garantito.

    Cosa salvare

    Prima ancora di scegliere strumenti, ho fatto la lista di cosa “duole” davvero perdere:

    Configurazioni di sistema: /etc dei vari host, unit systemd custom, vhost nginx/apache, certificati Let’s Encrypt

    Dati di servizi: database (Snipe-IT, Vikunja, Grafana, InfluxDB), volumi Docker persistenti

    Foto e documenti personali: archivio storico, scansioni, materiale di lavoro

    Codice sorgente: progetti personali, repo git che non vivono su forge remote

    Note e wiki: knowledge base personale

    ciò che invece NON salvo: ISO di OS (riscaricabili), cache di servizi, snapshot intermedi di backup (sarebbe ridondante).

    Strumenti

    Tre soli, ben rodati:

    rsync per copie incrementali rapide, locali e su NAS

    restic per backup cifrati deduplicati, locali e remoti

    rclone per portare backup verso object storage cloud su tier gratuiti

    Niente custom script complicati, niente backup tool esotici. Cose che funzionano da quindici anni e funzioneranno tra quindici.

    Layer 1: snapshot locali con rsync

    Ogni notte alle 02:00 un job cron fa snapshot delle directory critiche su un disco USB attaccato al server principale. Il comando:

    
    rsync -aH --delete --link-dest=/mnt/usb/backup/yesterday \
      /etc /home/user/Documenti /var/lib/docker/volumes \
      /mnt/usb/backup/today
    

    --link-dest fa hardlink ai file invariati rispetto a ieri: 30 giorni di snapshot occupano circa lo spazio di uno solo, più i delta. Ruoto today su yesterday con un secondo job mattutino.

    è il “recovery time” più veloce: copio indietro con cp -a e sono operativo in minuti.

    Layer 2: restic verso NAS

    Una volta al giorno, dopo gli snapshot rsync, lancio restic verso un repository sul NAS:

    
    restic -r /mnt/nas/restic backup /mnt/usb/backup/today \
      --exclude-caches --tag daily
    

    Restic è incrementale, cifrato con chiave persistente, deduplicato a livello blocco. La password del repo sta in due posti: gestore password e supporto offline cartaceo. Senza, nessun ripristino è possibile, neanche fisicamente.

    Layer 3: rclone verso object storage

    Settimanalmente sincronizzo il repo restic verso un bucket S3-compatibile su tier gratuito di un cloud provider:

    
    rclone sync /mnt/nas/restic OFFSITE_S3:dr-restic \
      --transfers 4 --bwlimit 5M
    

    --bwlimit 5M evita che il backup notturno saturi la mia banda. OFFSITE_S3 è un alias generico in ~/.config/rclone/rclone.conf, configurato con credenziali read-write per un singolo bucket, niente account-level.

    Layer 4: copia fredda offline

    Ogni due mesi giro un disco USB cifrato con LUKS, contenente l’ultima snapshot restic, e lo deposito a casa di un familiare. è il vero off-site, indipendente da qualunque cloud. Se domani tutti i miei cloud provider mi cancellassero l’account, avrei comunque una copia rilevante.

    Un caso reale

    Un martedì sera, verso le 21:00, l’SSD USB del mio server principale ha smesso di rispondere. SMART pulito fino al giorno prima, ma il dispositivo era diventato read-only per un crash del controller. Servizi giù: Snipe-IT, Vikunja, dashboard Grafana, repo git locali. Ho sostituito il disco con uno nuovo il mattino dopo, installato Debian fresco, ripristinato /etc e /var/lib/docker/volumes con un restic restore latest --target / dal repo NAS, e in due ore e mezza tutto era di nuovo online. RPO finale: 18 ore di dati persi (l’ultimo snapshot era della notte precedente). RTO: due ore e mezza dal momento del primo comando. Senza i tre layer mi sarei trovato a reinstallare e riconfigurare ogni servizio a mano, una giornata buona.

    Cosa funziona bene

    Più layer = più tranquillità. Anche se un layer si compromette (ransomware su cloud, NAS che muore, password persa), gli altri reggono. Restic deduplica e cifra in modo trasparente: il bucket cloud non vede mai dati in chiaro. Tutto è scriptabile e testabile fuori dall’emergenza.

    Limiti

    Il DR test è il pezzo che si tende a saltare. Una volta l’anno faccio un ripristino simulato su una macchina nuova, partendo solo dalla password restic e dall’accesso al bucket cloud. è scomodo, ma è l’unico modo per sapere se il piano funziona davvero. Restic verifica integrità via check, ma non garantisce che tu sappia ancora come usarlo dopo dieci mesi che non lo lanci.

    In pratica

    DR per un homelab non è un progetto enterprise, è una disciplina quotidiana di tre comandi automatizzati e un disco da ruotare ogni tanto. Costa meno di un servizio SaaS, dà più garanzie, ed è l’unica cosa che si parla davvero quando il disco fisico decide che oggi non gli va più di rispondere.


    Immagine generata con Cloudflare Workers AI / FLUX.

  • VPN mesh con Tailscale per la mia infrastruttura

    VPN mesh con Tailscale per la mia infrastruttura

    Tailscale è uno di quegli strumenti che ti fanno cambiare modo di pensare alla rete. Da quando l’ho introdotto nel mio homelab, ho smesso di configurare port forwarding sul router, certificati Wireguard a mano, regole NAT e DDNS. è diventato il tessuto connettivo invisibile fra tutti i miei device, dal portatile in casa fino a un piccolo server ARM su un tier gratuito di un provider cloud.

    Cos’è davvero

    Tailscale è una VPN mesh costruita sopra Wireguard. La parte interessante: il traffico non passa per un server centrale (il control plane fa solo coordinamento, distribuendo chiavi e aiutando il NAT traversal). I device si parlano peer-to-peer, cifrati, anche quando sono dietro NAT che normalmente sarebbero impenetrabili.

    Ogni device riceve un IP nel range CGNAT 100.64.0.0/10, persistente, raggiungibile da ogni altro device della tua tailnet. Niente DNS dinamico, niente “qual era l’IP pubblico oggi?”. Negli esempi userò indirizzi generici tipo 100.64.1.10 e 100.64.1.20, non quelli della mia tailnet.

    Installare

    Su Linux Debian/Ubuntu/Raspberry Pi OS:

    
    curl -fsSL https://tailscale.com/install.sh | sh
    sudo tailscale up
    

    Su macOS via brew o dall’App Store:

    
    brew install --cask tailscale
    

    Su Mac la app gira come menu bar item e si autentica con SSO al primo lancio.

    Su server headless preferisco il flag --ssh, così posso usare l’auth Tailscale invece di gestire chiavi SSH separate:

    
    sudo tailscale up --ssh --advertise-tags=tag:server
    

    Al primo up, apre un URL nel browser che porta alla pagina di Tailscale per autenticarsi (Google, Microsoft, GitHub o passkey). Da quel momento il device è nella tailnet.

    ACL e tag

    Tutti i device nella stessa tailnet di default possono parlarsi tutti con tutti. Per un homelab serio non basta, e l’ACL via tag è la prima cosa che configuro. Esempio di policy nella console web:

    
    {
      "tagOwners": {
        "tag:server":   ["autogroup:admin"],
        "tag:laptop":   ["autogroup:admin"],
        "tag:iot":      ["autogroup:admin"]
      },
      "acls": [
        { "action": "accept", "src": ["tag:laptop"], "dst": ["tag:server:22,80,443,8086"] },
        { "action": "accept", "src": ["tag:server"], "dst": ["tag:server:*"] }
      ]
    }
    

    I device taggati tag:iot non possono parlare con i server, ma solo con il gateway IoT dedicato. Il portatile arriva ai server solo su SSH, HTTP, HTTPS e InfluxDB. I server si parlano fra loro liberamente. Una compromissione su un device IoT è contenuta entro il suo segmento logico.

    Subnet router e exit node

    Quando ho un dispositivo che non posso o non voglio mettere in tailnet (vecchio NAS, stampante, switch), faccio annunciare la sua subnet a un Pi che è in tailnet:

    
    sudo tailscale up --advertise-routes=198.51.100.0/24 --advertise-tags=tag:server
    

    Dalla console web approvo la route. Da quel momento ogni device in tailnet può raggiungere quelle macchine direttamente per IP, senza che abbiano installato Tailscale loro stessi. Stesso meccanismo per l’exit node: un nodo in cloud annunciato come exit, e il portatile in viaggio ci dirige tutto il traffico per uscire da IP fissi.

    Un caso reale

    Una sera tardi, intorno alle 22:00, un familiare a 800 km mi ha chiesto aiuto con il suo piccolo homelab: un Raspberry Pi che faceva da Home Assistant non rispondeva più dall’esterno. Per anni avevamo gestito quel collegamento con port forwarding e DDNS, e ovviamente qualcosa nel router gli era cambiato dopo un update firmware. Invece di guidarlo passo passo in chiamata, gli ho installato Tailscale dal terminale con un curl ... | sh e un tailscale up. In tre minuti il suo Pi era nella tailnet, ho potuto fare SSH come se fosse nella mia stessa LAN, e ho fixato la sua configurazione in altri cinque. Da quel giorno il port forwarding sul suo router è disattivato e tutte le interazioni passano per la tailnet, cifrate e segmentate dalle ACL.

    Cosa funziona bene

    Tailscale taglia gli ostacoli di rete in modo sorprendente: NAT, CGNAT del provider, IPv6 incompatibile fra peer, non sono più problemi. MagicDNS dà nomi friendly ai device. Il free plan personale ha limiti più che generosi per un homelab (100 device, ACL illimitate). L’integrazione con SSO permette di legare l’identità a Google/Microsoft, e si revoca un device con un click se finisce per terra in tram.

    Limiti

    è un servizio proprietario centralizzato per il control plane: se Tailscale Inc. va offline, le nuove connessioni non partono (quelle stabilite continuano per un po’). Per chi vuole sovranità totale c’è Headscale, un control plane open source compatibile, che valuto periodicamente. Le ACL sono potenti ma vanno scritte con cura, perché un errore può aprire flussi non voluti fra tag.

    In pratica

    Tailscale è il sistema nervoso del mio homelab distribuito. Senza di lui dovrei gestire VPN site-to-site, certificati Wireguard, regole iptables a mano e DDNS. Con lui, la rete è semplicemente “tutto vede tutto secondo ACL”, e posso concentrarmi sul resto. è uno dei pochi servizi che, se sparisse domani, mi creerebbe più problemi che la perdita di un server fisico.


    Immagine generata con ComfyUI Mac M1 / RealVisXL V5 Lightning.

  • Esportare metriche di sistema centralizzate

    Esportare metriche di sistema centralizzate

    Tenere una dozzina di host monitorati senza centralizzare le metriche è come gestire una contabilità con post-it sparsi: funziona finché non serve davvero. Il mio stack attuale è Glances come collector locale, InfluxDB come time series database e Grafana come dashboard. è la terza iterazione del setup, dopo aver provato Telegraf+InfluxDB e Prometheus+node_exporter. Quello che lascio qui è la versione che gira oggi.

    Glances in modalità export

    Glances è nato come strumento “top-like” interattivo, ma supporta export verso una decina di backend, tra cui InfluxDB v2. L’idea: su ogni host gira glances come daemon che ogni dieci secondi pubblica le metriche verso un InfluxDB centrale.

    Installazione su Debian/Ubuntu:

    
    sudo apt install glances
    

    Per il supporto InfluxDB v2 mi serve la libreria Python:

    
    sudo apt install python3-influxdb-client
    

    Su Mac uso brew:

    
    brew install glances
    pip3 install influxdb-client
    

    Configurazione /etc/glances/glances.conf, sezione InfluxDB v2:

    
    [influxdb2]
    host=influx.example.local
    port=8086
    protocol=http
    org=homelab
    bucket=metrics
    token=GENERATO_DA_INFLUXDB_UI
    prefix=glances
    tags=host:nome-host
    

    Il token e l’org/bucket li creo via UI di InfluxDB. Il tag host mi consente di filtrare in Grafana per macchina.

    Lanciare Glances come servizio

    Niente script custom, uso il file unit di systemd che il pacchetto fornisce e creo un override per attivare l’export:

    
    sudo systemctl edit glances.service
    

    Aggiungo:

    
    [Service]
    ExecStart=
    ExecStart=/usr/bin/glances --export influxdb2 -q -t 10
    

    -q disabilita la UI (è un daemon), -t 10 aggiorna ogni dieci secondi. Poi:

    
    sudo systemctl enable --now glances.service
    

    InfluxDB centrale

    L’InfluxDB sta su un Raspberry Pi 5 con SSD USB (mai microSD per database). Installazione dai repo ufficiali InfluxData:

    
    wget -qO- https://repos.influxdata.com/influxdata-archive_compat.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/influxdata.gpg > /dev/null
    echo "deb https://repos.influxdata.com/debian stable main" | sudo tee /etc/apt/sources.list.d/influxdata.list
    sudo apt update
    sudo apt install influxdb2
    sudo systemctl enable --now influxdb
    

    Il primo setup, sulla porta 8086, definisce org homelab, bucket metrics con retention 30 giorni e token operatore. Il token operatore lo conservo offline, e creo un token write-only “glances” da distribuire sugli host: in questo modo se un host viene compromesso, l’attaccante può scrivere metriche fasulle ma non leggere o cancellare quelle altrui.

    Grafana sulla stessa macchina

    Grafana sta nello stesso Pi InfluxDB, repo ufficiale, datasource InfluxDB con token read-only. Dashboard “Glances v2” importata dal marketplace ufficiale Grafana, ID 17424. Mi mostra in un colpo d’occhio CPU, RAM, load, IO, network, top processes per host.

    Su Grafana imposto allerting nativo per soglie semplici: cpu_total > 80% per 10m, mem_used_pct > 90% per 5m, disk_used_pct > 85%. Notifiche via Telegram bot personale e email Resend.

    Un caso reale

    Un sabato mattina, verso le 9:00, ho aperto la dashboard per controllare i grafici prima del caffè e ho visto che l’host edge aveva avuto un picco di load avg 12.4 nelle quattro ore precedenti. CPU era stata al 100% per intervalli regolari. Ho guardato i top processes catturati da Glances: un cron mal configurato lanciava un import dati ogni cinque minuti invece che ogni cinque ore. Una virgola dimenticata nel crontab. Ho corretto e ho riallineato il job. Senza la cronologia centralizzata, il picco notturno me lo sarei perso, perché l’host era tornato in range per quando ho aperto la sessione SSH del mattino. Il bello di un time series database è esattamente questo: ti racconta cosa è successo quando tu non c’eri.

    Cosa funziona bene

    Glances è semplicissimo da installare e configurare, copre subito CPU, RAM, IO, network, processi, sensori. InfluxDB v2 con retention policy non si gonfia mai oltre i 5-6 GB di storage. Grafana è lo standard de facto e dashboard belle si trovano già fatte.

    Limiti

    Glances usa un po’ di RAM (50-80 MB per host) e su SBC molto vecchi (Raspberry Pi Zero) può essere troppo. L’export ogni dieci secondi è generoso per un homelab, ma se voglio cardinalità più alta devo passare a Telegraf. Per metriche applicative custom Glances non basta: aggiungo Prometheus scraper su porte specifiche, dove serve.

    In pratica

    Lo stack Glances+Influx+Grafana è il livello “infrastruttura di base” delle mie metriche. Sopra ci poggiano monitoring applicativi specifici (Observium per SNMP di rete, ping check serverless per uptime). Avere tre piani separati e indipendenti mi protegge dal classico problema “il monitoring è giù, quindi non so se è giù”: se Glances tace ma Observium grida, so subito da dove cominciare.


    Immagine generata con Cloudflare Workers AI / FLUX.

  • Monitoraggio di rete con SNMP senza diventare matti

    Monitoraggio di rete con SNMP senza diventare matti

    SNMP è uno di quei protocolli vecchi (RFC 1157 è del 1990) che continuano a funzionare bene proprio perché fanno una cosa sola: leggere contatori e variabili da apparati di rete. Per il mio homelab ho provato vari NMS prima di fermarmi su Observium Community, e dopo qualche tentativo sbagliato ho una configurazione che gira da oltre un anno senza farmi impazzire.

    Il mio setup

    Faccio girare Observium su un Raspberry Pi 5 8GB casalingo, con Debian (Raspberry Pi OS Lite 64-bit, ARM64). Lo storage è un SSD da 480 GB attaccato via USB 3.0, perché una microSD generica sotto MariaDB ha vita breve, lo so per esperienza diretta. Tutto ciò che è /var/lib/observium, /var/lib/mysql e /var/lib/observium/rrd finisce sull’SSD via bind mount. Sul Pi resta solo il sistema operativo, su una microSD ad alta affidabilità classe A2. La rete è ethernet gigabit, niente Wi-Fi per un servizio di monitoring che dipende dalla connettività.

    Observium su ARM64 funziona dai pacchetti community. Le dipendenze le installo dai repo Debian, prima di tutto:

    
    sudo apt update
    sudo apt install apache2 mariadb-server php php-mysql php-gd php-snmp \
      php-curl php-mbstring snmp snmpd fping mtr-tiny rrdtool whois ipmitool
    

    Poi clone del repository community:

    
    sudo mkdir -p /opt/observium
    cd /opt
    sudo git clone https://git.observium.org/observium.git observium
    

    In /opt/observium/config.php configuro utente DB dedicato (mai root MariaDB), password forte e $config['snmp']['version'] a 2c come default, con SNMPv3 dove possibile.

    Il bootstrap iniziale crea lo schema e la prima dashboard:

    
    cd /opt/observium
    sudo ./discovery.php -u
    

    Apache serve /opt/observium/html/ su una vhost interna, accessibile solo dalla LAN, mai esposta su internet pubblica.

    Agenti SNMP sui device

    Su ogni host Linux che voglio monitorare, installo snmpd:

    
    sudo apt install snmpd
    

    In /etc/snmp/snmpd.conf configuro una community string read-only con nome lungo e casuale (mai “public”), e limito l’accesso all’indirizzo del Pi monitoring:

    
    rocommunity SECRETSTRINGLUNGAACASO 203.0.113.10
    sysLocation studio
    sysContact [email protected]
    

    E faccio il bind solo sull’interfaccia che serve, non su 0.0.0.0:

    
    agentAddress udp:203.0.113.20:161
    

    Riavvio:

    
    sudo systemctl restart snmpd
    

    Sugli switch managed configuro la community via web UI o console, sempre v2c con community casuale per il read e v3 con username/password dove l’hardware lo permette. Niente RW community su nessun device, mai.

    Aggiungere device a Observium

    Dal Pi monitoring aggiungo un host:

    
    cd /opt/observium
    sudo ./add_device.php 203.0.113.20 SECRETSTRINGLUNGAACASO v2c
    

    Observium scopre interfacce, sensori, processi e li polla a cadenze diverse (default cinque minuti per i grafici, un minuto per gli alert). Dopo qualche ora la dashboard mostra throughput, errori, sensori di temperatura, e gli alert si attivano sulle soglie predefinite.

    Un caso reale

    Una sera, intorno alle 20:30, ho ricevuto un alert email da Observium per packet loss del 12% sull’interfaccia uplink dello switch principale. Latenza ping verso il gateway saliva oltre i 200 ms a tratti. Sono entrato sulla dashboard e ho visto il grafico storico: il packet loss era iniziato circa un’ora prima, in coincidenza con un picco di traffico verso WAN. Ho controllato il duplex sulla porta: half duplex invece di full. Un negoziato sbagliato dopo un riavvio dello switch del piano sopra. Cambio manuale del duplex a full, riavvio interfaccia, latenza tornata a 1-2 ms. Senza Observium avrei dato la colpa al provider e perso una mezz’ora a fare reload sul router. La cronologia SNMP, in questi casi, vale più di mille tcpdump.

    Cosa funziona bene

    Observium scopre automaticamente quasi tutto: interfacce, VLAN, sensori, processi monitorabili. La storia su RRD è leggerissima e si conserva per anni anche su SSD modesti. L’alerting via mail funziona, è essenziale, e quando un device sparisce ricevo notifica in pochi minuti.

    Limiti

    Il pacchetto community è in modalità “stable but slowly maintained”, e la UI ha sapore 2015. La Professional Edition costa, ma per un homelab la Community basta. SNMP è un protocollo verboso e non particolarmente sicuro: niente community RW, niente esposizione su WAN, e dove possibile SNMPv3 con autenticazione e cifratura.

    In pratica

    SNMP + Observium è la mia base storica di metriche di rete: throughput, errori, sensori. Glances + InfluxDB + Grafana gestiscono le metriche di sistema applicative. Sono due piani diversi che insieme mi danno una visione completa dell’homelab. SNMP non è bello, è efficace, ed è uno dei pochi strumenti che ti permettono di rispondere alla domanda “cosa stava succedendo alla rete tre mesi fa alle 22?” senza dover scrivere nulla in più.


    Immagine generata con Cloudflare Workers AI / FLUX.

  • Asset management per il tuo homelab con Snipe-IT

    Asset management per il tuo homelab con Snipe-IT

    Il mio homelab è cresciuto a strati: prima un Raspberry Pi, poi due, poi un mini PC, poi un piccolo server ARM su un tier gratuito di un provider cloud, qualche switch managed, una decina di cavi etichettati male. A un certo punto, in un assemblaggio domenicale, ho passato venti minuti a cercare un cavetto da console seriale che ero sicuro di avere “in quella scatola lì”. Ho aperto tre scatole, non l’ho trovato, e ho ordinato il quarto in vita mia. Quella sera ho deciso di mettere ordine.

    Snipe-IT è un asset management open source pensato per piccole aziende, ma scalato bene anche per chi ha un homelab di media complessità. Lo uso da un anno e mezzo per tracciare hardware, licenze, accessori e dove ho messo cosa.

    Installazione

    Lo faccio girare su un Raspberry Pi 5 8GB con Debian Bookworm, in container Docker. La compose minima:

    
    mkdir -p ~/snipeit && cd ~/snipeit
    curl -fsSL https://raw.githubusercontent.com/snipe/snipe-it/master/docker-compose.yml -o docker-compose.yml
    

    Edito il file .env per APP_URL, password DB e SMTP, poi:

    
    docker compose pull
    docker compose up -d
    

    Snipe-IT richiede MariaDB (incluso nel compose) e PHP 8.x. Il primo bootstrap inizializza il database ed emette la chiave APP_KEY: salvarla altrove subito, perché senza non si decifra il backup del database.

    Davanti metto un reverse proxy con Caddy o nginx e certificato Let’s Encrypt automatico. L’interfaccia parla HTTPS sul mio dominio interno, mai esposta su internet pubblica.

    Modello dati che uso

    Snipe-IT distingue Assets (oggetti seriali tipo un Raspberry Pi), Accessories (cose contate ma non singolarmente tracciate tipo cavi USB-C), Consumables (cose che si esauriscono tipo viti M3), Licenses (chiavi software con expiry), Components (RAM, dischi che sostituisco). Le categorie che ho creato:

    SBC: Raspberry Pi, Orange Pi, NanoPi

    Mini PC: NUC e simili

    Network gear: switch, AP Wi-Fi, router

    Storage: dischi USB, microSD etichettate, SSD da rotazione

    Cavi e adattatori: contati, non seriali

    Console: cavi seriali, programmer JTAG, alimentatori speciali

    Ogni asset seriale ha tag fisico stampato (DYMO 12mm) con asset tag univoco, modello, e tag categoria. Il tag fisico è la chiave per arrivare al record digitale in pochi secondi.

    Import bulk da CSV

    Quando ho fatto il primo censimento, l’inserimento manuale di trenta asset era già troppo. Ho preparato un CSV e usato l’importer:

    
    docker compose exec -T app php artisan snipeit:import --type=asset /tmp/assets.csv
    

    Il CSV deve avere intestazioni che mappano i campi (Asset Tag, Serial, Model Name, Category, Location, Status). Per i custom field ho aggiunto colonne mac_address e firmware_version che ho creato dal pannello.

    Un caso reale

    Un giovedì pomeriggio, intorno alle 15:00, un cliente mi ha chiesto la documentazione di un audit hardware su un suo lab di test. Volevo presentare lista, posizione, data acquisto e stato di garanzia per una ventina di macchine. Avevo registrato tutto su Snipe-IT nei mesi precedenti, comprese le scansioni delle fatture allegate come file ai singoli asset. In quindici minuti ho generato l’export CSV via API:

    
    curl -H "Authorization: Bearer TOKEN" \
      "https://snipeit.example.lan/api/v1/hardware?limit=100&offset=0" \
      -o assets.json
    

    E ho consegnato il foglio pulito. Senza Snipe-IT sarebbe stata una giornata di archeologia fra ricevute. Risparmio puro che paga da solo il costo di mantenere il servizio attivo.

    Cosa funziona bene

    La gestione checkout/checkin è preziosa: quando presto un cavo console a un cliente o porto un Pi a casa di un familiare per ricostruire un disastro, lo segno come “checked out” con data e nota. Tornato il pezzo, lo checko di nuovo in casa. Mai più “ma dove l’avevo lasciato?”. L’API REST è completa, l’ho integrata con uno script che, quando installo un nuovo host, registra automaticamente serial number e MAC.

    Limiti

    Snipe-IT richiede una manutenzione minima per restare utile: se smetti di aggiornarlo quando aggiungi o rimuovi hardware, in tre mesi diventa rumore. Il primo censimento è il lavoro più ingrato, conviene farlo a step (categorie principali prima, dettagli dopo) e accettare che sarà imperfetto per un po’.

    In pratica

    è una di quelle infrastrutture che paga in tranquillità più che in tempo risparmiato giornaliero. Tenere allineata la realtà fisica al database costa qualche minuto a settimana e ti restituisce ore quando arriva il momento del troubleshooting, dell’audit o del trasloco. Per chi è abituato a “tanto me lo ricordo”, il salto a Snipe-IT è quasi rieducativo.


    Immagine generata con ComfyUI Mac M1 / RealVisXL V5 Lightning.

  • Strategia backup Hot/Warm/Cold per chi parte da zero

    Strategia backup Hot/Warm/Cold per chi parte da zero

    Il backup, per chi gestisce un homelab, è la prima cosa che ci si dimentica di fare e l’ultima che si vorrebbe avere quando serve davvero. Io ci sono passato: ho perso una collezione di foto del 2014 perché “tanto era sul NAS” e il NAS era l’unica copia. Da quella volta ho adottato un modello hot/warm/cold un po’ rigido ma che mi tiene sereno la notte.

    Cos’è hot/warm/cold

    è un modo di classificare i dati in base a quanto spesso ti servono e quanto in fretta li devi rivedere:

    Hot: dati che cambiano spesso e che ti servono entro minuti. File di lavoro corrente, configurazioni di servizi, snapshot recenti di database. Storage veloce, locale o quasi.

    Warm: dati importanti ma non urgenti. Backup settimanali completi, archivi recenti. Object storage standard.

    Cold: archivi storici, snapshot vecchi, materiale che serve “se brucia la casa”. Archive tier, costo bassissimo, ripristino lento e con costo di estrazione.

    Idealmente i dati esistono in tre copie su due supporti diversi con una copia fuori sede: la regola 3-2-1. Hot/warm/cold è un modo pratico di implementarla.

    Tier HOT con Restic su HOT_LOCAL

    Restic fa snapshot incrementali deduplicati e cifrati. Lo uso verso un repository locale che chiamo categoricamente HOT_LOCAL, montato dal NAS in LAN: è veloce, locale, retention lunga senza pagare nulla in più.

    Init del repository:

    
    restic -r /mnt/HOT_LOCAL/restic init
    

    Backup notturno della cartella dati di un servizio:

    
    restic -r /mnt/HOT_LOCAL/restic backup /var/lib/mio-servizio
    

    Retention policy che applico settimanalmente:

    
    restic -r /mnt/HOT_LOCAL/restic forget \
      --keep-daily 14 --keep-weekly 8 --keep-monthly 12 --prune
    

    Il prune libera spazio davvero, perché senza di lui i dati cancellati restano nel repo finché non passa il garbage collector.

    Tier WARM su WARM_NFS e WARM_S3

    La copia warm vive in due sottocategorie. Lo snapshot settimanale del repo Restic finisce su un mount NFS dedicato in rete locale (WARM_NFS) e una copia compressa va su un bucket S3-compatibile (WARM_S3_GLACIER) configurato come alias rclone:

    
    rclone sync /mnt/HOT_LOCAL/restic WARM_S3_GLACIER:backup-restic \
      --transfers 4 --checkers 8
    

    sync riflette esattamente lo stato sorgente, quindi i file eliminati nel repo vengono eliminati anche sul bucket. Quando voglio mantenere una storia indipendente uso copy invece di sync.

    Tier COLD su COLD_S3_GLACIER

    Una volta al mese sposto i blocchi più vecchi di sei mesi in un bucket con storage class archive. Il comando rclone, con alias categoriale COLD_S3_GLACIER:

    
    rclone move /mnt/HOT_LOCAL/restic/snapshots-old COLD_S3_GLACIER:archivio \
      --min-age 180d
    

    In cold paghi pochissimo per lo storage e tanto per l’estrazione. Lo uso per cose che spero di non rivedere mai (foto del 2010, vecchi log archiviati per audit). Per i dati totalmente offline tengo anche un tier ulteriore che chiamo ICE_TAPE: un disco USB cifrato che giro ogni due mesi e tengo a casa di un familiare fidato. è il vero off-site, slegato da qualunque cloud.

    Un caso reale

    Un mercoledì sera, verso le 21:15, stavo refactoring uno script di import dati e ho lanciato un rm -rf su una sottocartella sbagliata: 180 GB di dataset analitico spariti. Restic mi ha salvato in 14 minuti netti. Ho lanciato restic restore latest --target /tmp/recover --include /var/lib/dataset puntando al repo HOT_LOCAL sul NAS, e ho ripreso il lavoro senza dover andare a tirare giù copie warm o cold. Il giorno dopo ho aggiunto un check periodico che verifica l’integrità del repo:

    
    restic -r /mnt/HOT_LOCAL/restic check --read-data-subset=10%
    

    Lo lancio ogni due settimane: legge il 10% dei blocchi e verifica gli hash. Mi protegge da repository corrotti silenziosamente, che è il peggior tipo di problema con i backup.

    Cosa funziona bene

    I tre tier sono autonomi e si validano a vicenda. Se mi muore il NAS, ho ancora warm. Se mi cancellano l’account cloud, ho ancora hot e cold offline. La cifratura Restic ha chiave persistente che tengo in due posti (gestore password + supporto offline), e senza quella nessun ripristino è possibile, neanche per chi possiede fisicamente i bucket.

    Limiti

    Restic ha un costo CPU notevole sul Raspberry Pi che fa da NAS, e una verifica completa di un repo da 1 TB richiede ore. La latenza di restore da tier cold è nell’ordine delle ore, talvolta della giornata. Bisogna pianificare un DR test almeno una volta l’anno, altrimenti sei sicuro di avere backup solo finché non provi a ripristinarli.

    In pratica

    Hot/warm/cold non è una architettura, è un modo di pensare ai dati. Lo applico anche a un homelab piccolo, perché obbliga a chiedersi “quanto in fretta deve tornare questo?” prima di scegliere lo strumento. Il risultato è che dormo bene, e nessun rm distratto mi può più rovinare un weekend.


    Immagine generata con Cloudflare Workers AI / FLUX.

  • Sincronizzazione file decentralizzata con Syncthing

    Sincronizzazione file decentralizzata con Syncthing

    Sincronizzare file fra macchine diverse senza affidarsi a un cloud di terzi è una di quelle abitudini che mi hanno cambiato il modo di lavorare. Sulla scrivania ho un portatile Linux, in salotto un Mac mini dedicato al multimedia, in un angolo un paio di Raspberry Pi e su un provider cloud un piccolo server ARM su tier gratuito. Tenere allineata la cartella ~/Documenti/note/ fra tutti questi posti, senza che nessuno legga i miei file, è il caso d’uso perfetto per Syncthing.

    Installare

    Su Debian e derivate, incluso Raspberry Pi OS, il pacchetto è nel repo ufficiale. Sul portatile uso fish come shell, sui server bash di default:

    
    sudo apt update
    sudo apt install syncthing
    

    Su Mac via Homebrew:

    
    brew install syncthing
    brew services start syncthing
    

    Sui sistemi headless lo abilito come servizio utente, sostituendo USERNAME con il mio utente di servizio:

    
    sudo systemctl enable --now [email protected]
    

    Il demone parte su 127.0.0.1:8384 per la web UI e su TCP/UDP 22000 per la sincronizzazione vera e propria. Se il server è remoto, faccio tunnel SSH per arrivare alla UI invece di esporla in rete:

    
    ssh -L 8384:127.0.0.1:8384 utente@host-remoto
    

    E apro http://127.0.0.1:8384 in locale. Esporre la web UI direttamente su internet è una pessima idea: l’autenticazione di default è basilare e da li si gestisce l’intera tailnet di file.

    Aggiungere un dispositivo

    Ogni nodo ha un Device ID lungo, generato alla prima esecuzione. Dalla web UI lo copio, sull’altro nodo apro “Add Remote Device” e lo incollo. Quando entrambi si vedono, posso condividere cartelle. Tre accortezze che applico sempre:

    1. Folder Type “Send & Receive” sulla macchina principale, “Receive Only” sui Raspberry Pi: un errore su un Pi non torna a sporcarmi il master.

    2. Versioning “Staggered” con retention a 30 giorni: salva snapshot a intervalli crescenti e mi permette di recuperare un file modificato per sbaglio anche tre settimane dopo.

    3. Ignore patterns per .DS_Store, .git/, node_modules/ e cartelle di cache: senza, Syncthing si mangia banda dietro a robaccia.

    Topologia e routing

    Per ridurre il traffico relay e tenere la sincronizzazione veloce, configuro un nodo come “Introducer” e abilito il discovery globale solo dove serve. Sui server in cloud con IP pubblico aggiungo l’hint statico nel device address: invece di dynamic metto tcp://203.0.113.10:22000. In questo modo il NAT traversal è immediato e non serve passare dai relay pubblici Syncthing.

    Le porte 22000/tcp e 22000/udp sui server vanno aperte nel security group o sull’host firewall:

    
    sudo ufw allow 22000/tcp
    sudo ufw allow 22000/udp
    

    Un caso reale

    Una mattina, intorno alle 9:30, stavo lavorando su un Raspberry Pi della stanza-studio quando ho dovuto spostarmi al portatile per un ticket urgente. Apro il laptop e in venti secondi la cartella note è già aggiornata con quello che avevo scritto sul Pi. Niente upload manuali, niente “lascia perdere, lo finisco poi”. Quattro ore dopo, al rientro, ho notato che un service di un host periferico aveva ricreato per errore qualche file dentro node_modules in una cartella condivisa per sbaglio: la Receive Only di quel nodo ha bloccato la propagazione, ho potuto fare cleanup centralmente senza rincorrere copie sporche su tre macchine.

    Cosa funziona bene

    La filosofia peer-to-peer mi piace: i file restano miei, cifrati in transito, e non c’è nessun servizio centrale che vede i metadati. Lo Staggered Versioning mi ha salvato almeno tre volte da rm sbagliati. La UI è chiara, lo stato di ogni cartella è leggibile a colpo d’occhio.

    Limiti

    Per cartelle con tantissimi file piccoli (un cache di build, una libreria con migliaia di assets) Syncthing fatica e il CPU sul Raspberry Pi schizza. Per quei casi continuo a usare rsync puntuale o uno share NFS. Il primo handshake fra device dietro NAT a volte richiede un paio di minuti, soprattutto se la rete del provider cloud blocca certi flussi UDP.

    In pratica

    Syncthing è diventato il livello di trasporto file dell’homelab: copre la mia esigenza di “stessi file, ovunque”, senza che nessuno si metta in mezzo. Lo accoppio con backup a freddo per il disaster recovery e con un object storage S3-compatibile per il versioning storico, ma per il quotidiano è lui che fa il lavoro.


    Immagine generata con ComfyUI Mac M1 / RealVisXL V5 Lightning.

  • Monitoraggio serverless senza costi fissi

    Monitoraggio serverless senza costi fissi

    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.