Un dashboard self-hosted (homepage, nell'elenco dei servizi self-hosted) raccoglie i collegamenti e lo stato dei servizi dell'homelab in un'unica pagina. Il repository pubblico del mio è un modello con segnaposto ({{VARIABILE}}, domini di esempio): questa guida racconta cosa è servito per riportarlo ai dati reali, due problemi tecnici incontrati lungo il percorso e perché ho poi affiancato un secondo strumento, Glance, invece di sostituirlo.
Dal modello pubblico ai dati reali
Il repository scaricabile contiene la struttura (file di configurazione per servizi, impostazioni, widget, segnalibri) ma non i valori reali, per ovvie ragioni di sicurezza. Per ripopolarlo serviva prima recuperare la configurazione effettiva dal container LXC che esegue il dashboard: entrarci, individuare dove vive la configurazione (bind mount Docker o percorso diretto) e leggerla. Da lì, riscrivere ogni file con l'elenco reale dei servizi — backup, gestione foto, controllo di disponibilità, DNS con filtraggio, reverse proxy — mantenendo nel repository pubblico solo struttura e segnaposto, mai gli indirizzi reali.
Il problema del copia-incolla: dati binari troncati
Trasferire testo semplice da un terminale a un altro è banale; trasferire un'icona (un PNG codificato in base64) lo è molto meno. Un primo tentativo con base64 -w0 (output su una riga sola) arrivava tagliato: da circa 5.600 caratteri attesi, ne risultavano appena 646. La causa non era la codifica ma il trasporto: una singola riga molto lunga veniva troncata nel passaggio tra terminale e client.
La correzione immediata è stata banale — ripetere la codifica senza -w0, così l'output si spezza su più righe più corte e il copia-incolla arriva intatto. Per un'icona più pesante (un avatar da 280 KB), però, anche questo non bastava: la soluzione è stata leggere l'immagine direttamente dal browser già autenticato sul dashboard live, estrarne i byte via canvas e ricostruire il file in locale, verificando alla fine che dimensione e firma del file corrispondessero all'originale byte per byte.
Nota
Per i trasferimenti piccoli un dettaglio come il wrapping delle righe fa la differenza tra un file valido e uno corrotto senza errori evidenti: vale la pena controllare sempre la dimensione del file arrivato contro quella attesa, non solo che "qualcosa" sia arrivato.
Il bug vero: un commento CSS non chiuso
Il dashboard aveva un filigrana (watermark) nel logo che non compariva più. Nessun errore in console, nessun log: il CSS personalizzato (custom.css) semplicemente non applicava più la regola. Ispezionando l'elemento dal vivo (getComputedStyle sullo pseudo-elemento ::before del logo), la proprietà content risultava none e position static: come se quella regola non fosse mai stata scritta.
La causa era un commento CSS aperto e mai chiuso, più in alto nel file: tutto quello che veniva dopo — inclusa l'intera regola body::before che disegnava la filigrana — era stato silenziosamente inghiottito nel commento. Restava attiva solo una seconda regola, dentro una media query per schermi piccoli, che modificava un elemento ormai privo della sua definizione di base: nessun errore di sintassi, nessun avviso, solo un pezzo di interfaccia sparito.
/* qualche nota legittima
.logo-wrapper { ... } /* <- questa riga chiude il commento sbagliato */
body::before { content: ""; /* MAI eseguita: resta dentro il commento aperto */
position: fixed;
...
}Un commento CSS non chiuso non genera un errore: zittisce tutto quello che segue, fino al prossimo */ che incontra (anche se non era quello voluto). È uno dei bug più subdoli perché il browser non segnala nulla: la pagina si carica, gli stili si applicano, solo un pezzo manca. L'unico modo per trovarlo è stato confrontare il file live con una copia ricostruita byte per byte e leggere il CSS riga per riga a ritroso dal punto in cui la regola avrebbe dovuto applicarsi.
Dall'inventario del cluster a un secondo dashboard
Con l'accesso diretto all'interfaccia di Proxmox, costruire un inventario preciso del cluster è diventato più semplice: interrogare le API del cluster restituisce nodi, macchine virtuali e container con stato e indirizzo di ciascuno. I servizi assegnati via DHCP, però, cambiano indirizzo a ogni riavvio se non sono spenti: per quelli fermi l'indirizzo non è noto finché non vengono riaccesi, un limite da tenere presente prima di affidarsi a un indirizzo "scoperto" una tantum (meglio una riserva DHCP o un indirizzo statico per tutto ciò che un dashboard deve raggiungere in modo stabile).
Da quell'inventario è nata la configurazione di un secondo strumento, Glance, pensata per coprire prima solo i servizi effettivamente accesi al momento, con un blocco commentato pronto per i servizi spenti da completare quando verranno riattivati con un indirizzo stabile. Non sostituisce homepage: in questa fase dell'homelab convivono più dashboard mentre valuto quale tenere.
La lezione
Due lezioni pratiche, utili oltre questo caso specifico: primo, quando un trasferimento di dati binari sembra "andato a buon fine" ma il risultato si comporta in modo strano, controllare sempre dimensione e firma del file prima di cercare il bug altrove. Secondo, un'interfaccia che smette di funzionare senza errori in console è un indizio forte di un problema di sintassi silenzioso — nel CSS, un commento non chiuso — non di un problema logico: va cercato leggendo il file, non debuggando il comportamento.