<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://www.francescolavella.it/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.francescolavella.it/" rel="alternate" type="text/html" /><updated>2026-08-14T10:40:27+00:00</updated><id>https://www.francescolavella.it/feed.xml</id><title type="html">francesco la vella</title><subtitle>su di me e altre storie</subtitle><entry><title type="html">Coolify: la nuova gestione dei siti WordPress e dei progetti Sintab</title><link href="https://www.francescolavella.it/coolify-siti-wordpress-sintab/" rel="alternate" type="text/html" title="Coolify: la nuova gestione dei siti WordPress e dei progetti Sintab" /><published>2026-08-14T00:00:00+00:00</published><updated>2026-08-14T00:00:00+00:00</updated><id>https://www.francescolavella.it/coolify-siti-wordpress-sintab</id><content type="html" xml:base="https://www.francescolavella.it/coolify-siti-wordpress-sintab/"><![CDATA[<p>Per Sintab gestisco personalmente tutta l’infrastruttura IT, siti web compresi. Fino a poco fa questo significava la solita costellazione di hosting condivisi e pannelli tradizionali: un account per cliente, deploy via FTP o wp-admin, backup affidati al plugin di turno o al provider, nessuna visione d’insieme se non aprendo un pannello alla volta. Funzionava, ma ogni sito nuovo era lavoro manuale che si ripeteva identico, e ogni verifica (“è aggiornato tutto? i backup vanno a buon fine? c’è un sito con un plugin allo sbando?”) richiedeva un giro a mano su ognuno.</p>

<p>Nell’ultimo mese ho spostato tutto su <strong>Coolify</strong>, un PaaS self-hosted open source, installato su un server che gestisco io su Hetzner. Oggi una dozzina di siti WordPress di Sintab e dei suoi progetti (formazione, e-commerce interni, portali corsi) girano lì come container, insieme a n8n, Filebrowser e qualche altro servizio. Ma la parte che mi interessa raccontare non è “ho installato Coolify” — è l’insieme di script che ci ho costruito intorno, perché è lì che si è fatto il lavoro vero.</p>

<h2 id="un-comando-per-un-sito-nuovo">Un comando per un sito nuovo</h2>

<p>Il primo problema era che aprire un sito nuovo restava un rito manuale: creare l’app, il database, i domini, le variabili d’ambiente, il backup, e ricordarsi ogni volta un dettaglio che la volta prima avevo dimenticato. Ho scritto <code class="language-plaintext highlighter-rouge">nuovo-sito.sh</code>, che prende nome e dominio e fa tutto passando dall’API di Coolify: crea un MariaDB gestito, un’Application buildata dal repo git via Dockerfile, un volume persistente su <code class="language-plaintext highlighter-rouge">/var/www/html</code>, le variabili d’ambiente (tutte <strong>runtime</strong>, mai build-time — altrimenti la password del database finisce nella history dell’immagine Docker), attiva il backup automatico schedulato, fa il primo deploy e infine aggancia il sito a Filebrowser.</p>

<p>Un paio di cose imparate a mie spese sono finite come commenti nello script stesso, perché altrimenti le avrei dimenticate di nuovo:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># I domini si passano ADESSO, alla creazione: Coolify genera le label Traefik
# una sola volta e le salva sull'Application. Cambiare fqdn dopo non le
# rigenera, e il container resta con le label del dominio vecchio -&gt; 503.
</code></pre></div></div>

<p>La primissima versione, prima ancora di questo script, generava a mano un <code class="language-plaintext highlighter-rouge">docker-compose</code> e lo spingeva via API come Service. Funzionava, ma disattivava i backup automatici di Coolify (funzionano solo sulle risorse che gestisce lui) e teneva la configurazione fuori da git. L’ho sostituita perché un sistema comodo ma che rinuncia ai backup gestiti non è un compromesso accettabile.</p>

<h2 id="backup-che-si-scoprono-da-soli">Backup che si scoprono da soli</h2>

<p>Il pezzo a cui tengo di più è <code class="language-plaintext highlighter-rouge">backup-siti.sh</code>. La prima versione aveva l’elenco dei siti scritto a mano in cima allo script. Ha smesso di andarmi bene l’11 agosto, quando uno dei siti è passato da Service ad Application su Coolify e il volume ha cambiato nome: l’elenco fisso avrebbe continuato a salvare un volume ormai morto, senza dare nessun errore. Un backup che sembra riuscito ma salva il nulla è peggio di un backup che fallisce rumorosamente.</p>

<p>Ora lo script non ha nessun elenco: scopre i siti interrogando i container in esecuzione per la variabile d’ambiente <code class="language-plaintext highlighter-rouge">WORDPRESS_DB_NAME</code>, e da lì risale a utente, password e volume dei file. Se conta meno siti del minimo atteso, si ferma <strong>prima</strong> di scrivere qualsiasi cosa e prima della potatura delle copie vecchie — una copia incompleta che sovrascrive le buone è peggio di nessuna copia.</p>

<p>L’altro cambiamento è dove finiscono le copie offsite. Prima versione upload S3 integrato di Coolify verso Backblaze B2. È bastato che un plugin di export generasse un <code class="language-plaintext highlighter-rouge">.wpress</code> da 7,4 GB più due tentativi di upload troncati per saturare il piano gratuito e mandare l’intero account in blocco scrittura. Ho tolto Backblaze e sono passato a un <strong>Hetzner Storage Box</strong> via <code class="language-plaintext highlighter-rouge">rclone</code>, con verifica hash dopo ogni copia e potatura esplicita (<code class="language-plaintext highlighter-rouge">copy</code>, non <code class="language-plaintext highlighter-rouge">sync</code>: se svuoto per errore la cartella locale non voglio che la notte dopo si porti dietro anche l’offsite).</p>

<h2 id="manutenzione-settimanale-senza-aprire-venti-pannelli">Manutenzione settimanale senza aprire venti pannelli</h2>

<p><code class="language-plaintext highlighter-rouge">maintenance-check.sh</code> gira ogni lunedì e mi manda un report via email. Controlla se le immagini Docker esterne (WordPress, PHP, MariaDB, n8n) hanno una patch più recente sullo stesso tag, e soprattutto confronta il <strong>commit effettivamente deployato</strong> con la HEAD remota del branch di ogni sito — senza bisogno di un checkout locale dei repository, dato che ormai tutto vive dentro Coolify. Il trucco è che il tag dell’immagine Docker di ogni Application è lo SHA del commit buildato: basta un <code class="language-plaintext highlighter-rouge">git ls-remote</code> per sapere se un sito è rimasto indietro rispetto a <code class="language-plaintext highlighter-rouge">main</code>. Lo stesso report controlla lo stato HTTP di ogni dominio e le risorse del server.</p>

<h2 id="accesso-ai-file-senza-passare-da-me">Accesso ai file senza passare da me</h2>

<p>L’ultimo pezzo, <code class="language-plaintext highlighter-rouge">filebrowser-sync.sh</code>, risolve un problema più organizzativo che tecnico: qualcuno in ufficio deve poter aprire i file di un sito senza chiedermi ogni volta una chiave SSH. Filebrowser gira come servizio su Coolify con l’IP dell’ufficio (o la VPN) in allowlist, e i suoi mount vengono <strong>rigenerati da zero</strong> ogni volta a partire dallo stato reale — quali volumi esistono davvero, montati su <code class="language-plaintext highlighter-rouge">/var/www/html</code> — invece che aggiunti in coda uno alla volta. È idempotente e si autoripara: se un sito viene cancellato, sparisce anche dal mount; se ne nasce uno nuovo, <code class="language-plaintext highlighter-rouge">nuovo-sito.sh</code> lo aggancia da solo come ultimo passo.</p>

<h2 id="cosa-cambia-in-sostanza">Cosa cambia, in sostanza</h2>

<p>Non è solo “ora è tutto su Docker invece che su hosting condivisi”. È che gli script non si fidano più di un elenco scritto una volta e mai più aggiornato: interrogano lo stato reale — i container in esecuzione, i volumi montati, i commit deployati — ogni volta che girano. I due incidenti che li hanno plasmati (il volume rinominato, l’account Backblaze bloccato da un export troppo pesante) sono diventati controlli scritti nel codice, non note a margine da ricordarsi a memoria. Per una dozzina di siti gestiti da una persona sola, è la differenza tra dormire tranquillo e sperare che nessuno faccia domande scomode di lunedì mattina.</p>]]></content><author><name></name></author><category term="post" /><category term="sysadmin" /><category term="wordpress" /><category term="coolify" /><category term="docker" /><category term="automazione" /><category term="sintab" /><summary type="html"><![CDATA[Ho spostato tutti i siti WordPress che gestisco per Sintab da hosting e pannelli tradizionali a Coolify, su un server mio. Il risultato non è solo 'più comodo': sono script che scoprono lo stato reale invece di fidarsi di un elenco scritto a mano.]]></summary></entry><entry><title type="html">Francesco La Vella Ads Tools</title><link href="https://www.francescolavella.it/ads-automation-tool/" rel="alternate" type="text/html" title="Francesco La Vella Ads Tools" /><published>2026-08-04T00:00:00+00:00</published><updated>2026-08-04T00:00:00+00:00</updated><id>https://www.francescolavella.it/ads-automation-tool</id><content type="html" xml:base="https://www.francescolavella.it/ads-automation-tool/"><![CDATA[<h2 id="cosa-è">Cosa è</h2>

<p><strong>Francesco La Vella Ads Tools</strong> è un progetto personale che ho costruito per automatizzare alcune operazioni ricorrenti sul mio account Google Ads: estrazione di report, controlli periodici sullo stato delle campagne e aggiornamento di alcuni parametri (budget, stato degli annunci) in base a regole che decido io.</p>

<p>Non è un prodotto destinato ad altri utenti: è un tool che uso esclusivamente per la gestione dei miei account pubblicitari personali.</p>

<h2 id="come-funziona">Come funziona</h2>

<p>Il progetto è costruito attorno a <a href="https://n8n.io">n8n</a>, uno strumento di automazione a workflow open source che eseguo su un mio server. I workflow si collegano alla <strong>Google Ads API</strong> tramite OAuth 2.0, con il mio account Google come unico utente autorizzato.</p>

<p>In pratica il workflow interroga periodicamente l’API per leggere le performance delle campagne, genera report che ricevo automaticamente, e in alcuni casi esegue modifiche puntuali (ad esempio pausare un annuncio sotto una certa soglia di rendimento) secondo regole che ho definito io. I dati settimanali estratti vengono inoltre scritti in un foglio Google Sheets personale, che uso come archivio e per costruire grafici di andamento.</p>

<h2 id="quali-dati-richiedo-e-perché">Quali dati richiedo e perché</h2>

<p>Per funzionare, l’app richiede l’autorizzazione OAuth ai seguenti scope Google:</p>

<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">https://www.googleapis.com/auth/adwords</code></strong> — accesso in lettura e scrittura al mio account Google Ads. Mi serve per leggere le metriche di rendimento delle campagne (impression, click, spesa, conversioni) e per applicare modifiche puntuali che ho definito io stesso, come la pausa di un annuncio sotto una certa soglia di rendimento.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">https://www.googleapis.com/auth/spreadsheets</code></strong> — accesso in lettura e scrittura ai fogli di calcolo Google Sheets. Mi serve per scrivere ogni settimana i dati estratti da Google Ads in un foglio personale che uso come archivio storico.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">https://www.googleapis.com/auth/drive.file</code></strong> — accesso limitato ai soli file creati o aperti tramite questa app. Mi serve perché n8n, per scrivere su Google Sheets, deve poter individuare il foglio specifico che ho indicato.</li>
</ul>

<p>Non viene richiesto alcun accesso a dati di altri utenti: l’unico account collegato è il mio.</p>

<h2 id="dati-e-privacy">Dati e privacy</h2>

<p>I dati letti dall’API restano tra il mio account Google Ads e il mio workflow n8n, eseguito su un server che gestisco personalmente. Non vengono raccolti, condivisi o ceduti a terzi, e non vengono usati per finalità diverse da quella descritta sopra.</p>

<p>L’informativa completa sul trattamento dei dati è disponibile nella <a href="/PrivacyPolicy/">Privacy Policy</a> del sito.</p>

<h2 id="contatti">Contatti</h2>

<p>Per qualsiasi domanda su questo progetto puoi contattarmi ai recapiti indicati nella pagina <a href="/about">About</a>.</p>]]></content><author><name></name></author><category term="google-ads" /><category term="automazione" /><category term="n8n" /><category term="api" /><summary type="html"><![CDATA[Uno strumento personale che uso per automatizzare la gestione e il reporting delle mie campagne Google Ads.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.francescolavella.it/assets/img/profile-300.jpg" /><media:content medium="image" url="https://www.francescolavella.it/assets/img/profile-300.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Memoria condivisa per Claude Code, su un server tutto mio</title><link href="https://www.francescolavella.it/claude-mem-condiviso-myserver/" rel="alternate" type="text/html" title="Memoria condivisa per Claude Code, su un server tutto mio" /><published>2026-07-23T00:00:00+00:00</published><updated>2026-07-23T00:00:00+00:00</updated><id>https://www.francescolavella.it/claude-mem-condiviso-myserver</id><content type="html" xml:base="https://www.francescolavella.it/claude-mem-condiviso-myserver/"><![CDATA[<p>Da un po’ uso <a href="https://github.com/thedotmack/claude-mem">claude-mem</a>, un plugin per Claude Code che trasforma ogni sessione in osservazioni compresse e le ripropone nelle sessioni successive: niente più “allora, come ti dicevo ieri…”. Il problema è che la memoria vive in un database SQLite locale, dentro <code class="language-plaintext highlighter-rouge">~/.claude-mem</code>. Locale, appunto.</p>

<p>E io — l’ho già raccontato parlando di <a href="/upgrade-totale-claude-code/">questo stesso blog</a> — lavoro da più postazioni. Ogni macchina aveva la sua memoria, isolata dalle altre. Cominciare una sessione sul portatile senza il contesto accumulato al fisso in studio, ogni volta, era esattamente il problema che claude-mem dovrebbe risolvere.</p>

<h2 id="le-opzioni-sul-tavolo">Le opzioni sul tavolo</h2>

<p>claude-mem offre già un modo per sincronizzare tra macchine: <strong>cmem.ai</strong>, un servizio cloud della stessa softwarehouse, con un hub proprietario (un Cloudflare Worker per utente) che fa da centro sync. Comodo, supportato, zero configurazione oltre a un token. Ma significa caricare su un’infrastruttura di terzi le narrazioni delle mie sessioni di lavoro — che spesso includono cose di clienti e progetti aziendali. Per uso personale forse ci avrei anche pensato, ma non con dati che non sono solo miei.</p>

<p>Ho controllato se esistesse un modo per auto-ospitare quello stesso hub. Non esiste: ho trovato una discussion su GitHub dove il maintainer conferma che no, self-hosted non è previsto, e gli script di export/import manuale sono anche rotti (<code class="language-plaintext highlighter-rouge">FOREIGN KEY constraint failed</code>, per chi è curioso). Altra strada scartata: montare la cartella <code class="language-plaintext highlighter-rouge">~/.claude-mem</code> via rete (NFS o sshfs) e condividerla tra macchine. SQLite in WAL mode — quello che usa claude-mem — sopra un filesystem di rete è una ricetta nota per corruzione dei dati: il locking a byte-range che il WAL richiede spesso non è implementato correttamente da quei filesystem. Meglio di no.</p>

<p>La soluzione più semplice, alla fine, era anche la più ovvia: invece di sincronizzare un database tra macchine diverse, eliminare le macchine diverse. Un solo posto dove il database vive, e ci si collega da dovunque via SSH.</p>

<h2 id="un-server-hetzner-per-tutto">Un server Hetzner per tutto</h2>

<p>Da un po’ ho messo su un server su Hetzner che uso come base per gestire tutti i miei progetti — repository, ambienti di lavoro, servizi che devono girare in modo continuo. Ci si accede via SSH, con un alias dedicato nel mio <code class="language-plaintext highlighter-rouge">~/.ssh/config</code>. Era la casa naturale anche per claude-mem: un solo posto, sempre acceso, che già considero “il mio server” per tutto il resto.</p>

<h2 id="linstallazione-tre-runtime-non-uno">L’installazione: tre runtime, non uno</h2>

<p>Qui la parte tecnicamente interessante. claude-mem non gira solo su Node: il suo worker daemon usa <code class="language-plaintext highlighter-rouge">bun:sqlite</code> per parlare col database, quindi richiede <strong>Bun</strong>, non solo Node.js. E per la ricerca semantica usa <strong>Chroma</strong> via <code class="language-plaintext highlighter-rouge">chroma-mcp</code>, lanciato con <code class="language-plaintext highlighter-rouge">uvx</code> — quindi serve anche <strong>uv</strong>, il gestore di pacchetti Python di Astral. Tre runtime diversi (Node, Bun, uv) per un plugin che sulla carta “aggiunge memoria a Claude Code”.</p>

<p>Sul server nuovo, nessuno dei tre era installato. Li ho messi su tutti in user-space, senza toccare i pacchetti di sistema (a parte <code class="language-plaintext highlighter-rouge">unzip</code>, richiesto dall’installer di Bun):</p>

<ul>
  <li>Node 22 via <code class="language-plaintext highlighter-rouge">nvm</code></li>
  <li>Bun via il suo installer ufficiale</li>
  <li><code class="language-plaintext highlighter-rouge">uv</code>/<code class="language-plaintext highlighter-rouge">uvx</code> via l’installer di Astral</li>
</ul>

<p>Poi marketplace e plugin con la CLI di Claude Code stessa:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>claude plugin marketplace add thedotmack/claude-mem
claude plugin install claude-mem@thedotmack
</code></pre></div></div>

<p>Il primo tentativo di avvio ha subito segnalato nei log l’assenza di Bun (“worker daemon requires Bun because it uses bun:sqlite”). Installato Bun, il worker si è avviato ma senza ricerca semantica (“uvx executable not found for chroma-mcp”). Installato anche <code class="language-plaintext highlighter-rouge">uv</code>, riavviato il worker, e al terzo giro tutti i pezzi hanno agganciato: sessione registrata nel database, Chroma connesso, nessun errore nei log.</p>

<h2 id="un-alias-per-non-pensarci-più">Un alias per non pensarci più</h2>

<p>Il login di Claude Code resta l’unico passaggio davvero manuale — richiede il browser, quindi va fatto una volta a mano dentro una sessione <code class="language-plaintext highlighter-rouge">tmux</code> sul server (per non perderlo se cade la connessione SSH). Fatto quello, ho aggiunto un alias in <code class="language-plaintext highlighter-rouge">.bashrc</code> che riassume tutto il flusso quotidiano:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>alias mc='ssh -t myserver "tmux new-session -A -s claude claude"'
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">tmux new-session -A</code> crea la sessione se non esiste, altrimenti si riattacca a quella già viva — quindi la prima volta apre <code class="language-plaintext highlighter-rouge">claude</code>, le volte dopo ritrovo la sessione esattamente dove l’avevo lasciata, da qualsiasi postazione digiti <code class="language-plaintext highlighter-rouge">mc</code>.</p>

<h2 id="cosa-cambia-davvero">Cosa cambia, davvero</h2>

<p>Non lavoro più “in locale” quando uso Claude Code per certe cose: lavoro dentro il server, e i progetti che voglio che claude-mem osservi devono vivere lì. È un cambio di abitudine, non solo di configurazione. In cambio ho un solo database SQLite, mai conteso da due macchine insieme, senza rischio di corruzione da filesystem di rete e senza che una singola riga delle mie sessioni finisca su un cloud che non controllo. Per il tipo di lavoro che faccio — clienti, dati aziendali, roba che non è solo mia da condividere — mi sembra il compromesso giusto.</p>]]></content><author><name></name></author><category term="post" /><category term="ai" /><category term="linux" /><category term="sysadmin" /><category term="sqlite" /><summary type="html"><![CDATA[Ho spostato claude-mem su un server centrale via SSH, per avere la stessa memoria su tutte le postazioni senza affidare le mie sessioni di lavoro a un cloud di terzi.]]></summary></entry><entry><title type="html">Upgrade totale del sito con claude code</title><link href="https://www.francescolavella.it/upgrade-totale-claude-code/" rel="alternate" type="text/html" title="Upgrade totale del sito con claude code" /><published>2026-05-01T00:00:00+00:00</published><updated>2026-05-01T00:00:00+00:00</updated><id>https://www.francescolavella.it/upgrade-totale-claude-code</id><content type="html" xml:base="https://www.francescolavella.it/upgrade-totale-claude-code/"><![CDATA[<p>Questo blog gira da anni su un tema Jekyll che mi ero portato dietro praticamente intatto: avatar nel cerchio rosso, titolo in Lobster, qualche effetto blur quando apri il menu. Funzionava, e per quel motivo non lo avevo mai toccato sul serio. Ho aperto Claude Code una sera con un’idea molto vaga — “leggi tutto il progetto, verifica se ci sono ottimizzazioni da attuare” — e nel giro di qualche ora il sito è cambiato da dentro pur restando, in superficie, lo stesso sito.</p>

<h2 id="tre-postazioni-e-un-repo">Tre postazioni e un repo</h2>

<p>Il primo passo è stato risolvere un mio problema operativo: scrivo da tre macchine diverse — fisso di casa, portatile, fisso in studio — e fino a poco fa il workflow era fragile. Ora lavoro su un repo Git, con la stessa cartella sincronizzata via GitHub, e su ognuna delle tre postazioni ho <code class="language-plaintext highlighter-rouge">claude</code> configurato allo stesso modo. Apro il terminale, <code class="language-plaintext highlighter-rouge">git pull</code>, lavoro, <code class="language-plaintext highlighter-rouge">git push</code>. La parte interessante è che Claude Code legge davvero il progetto: i <code class="language-plaintext highlighter-rouge">_posts</code>, i layout, gli SCSS, persino i plugin Ruby in <code class="language-plaintext highlighter-rouge">_plugins/</code>. Questo significa che le modifiche non sono mai a tentoni — sono sempre ancorate a quello che c’è già.</p>

<h2 id="i-bug-che-vivevano-da-otto-anni">I bug che vivevano da otto anni</h2>

<p>L’audit iniziale ha tirato fuori cose imbarazzanti. Il filtro <code class="language-plaintext highlighter-rouge">{{ content | liquify }}</code> in <code class="language-plaintext highlighter-rouge">_layouts/post.html</code> puntava a una gem che nel <code class="language-plaintext highlighter-rouge">Gemfile.lock</code> non esisteva, quindi non faceva niente da chissà quanto. Otto layout caricavano jQuery 3.2.1 da CDN e contemporaneamente, dentro <code class="language-plaintext highlighter-rouge">scripts.html</code>, veniva caricata anche la 1.12.2 — due jQuery diversi sulla stessa pagina, uno che si sovrascriveva l’altro. Il plugin custom <code class="language-plaintext highlighter-rouge">youtube.rb</code> aveva l’href dell’embed <em>hardcoded</em> a un video specifico: in pratica ogni <code class="language-plaintext highlighter-rouge">{% youtube %}</code> puntava sempre allo stesso video sbagliato. Ventidue link <code class="language-plaintext highlighter-rouge">target="_blank"</code> senza <code class="language-plaintext highlighter-rouge">rel="noopener"</code> — vulnerabilità da reverse-tabnabbing che è lì da sempre.</p>

<p>Pulizia: jQuery via, sostituito da una novantina di righe di vanilla JS in <code class="language-plaintext highlighter-rouge">assets/js/menu.js</code> e <code class="language-plaintext highlighter-rouge">assets/js/goup.js</code>. Gli script inline duplicati negli otto layout — quaranta righe ciascuno, sempre uguali — diventati un singolo <code class="language-plaintext highlighter-rouge">&lt;script defer src="menu.js"&gt;</code>. Il filtro morto rimosso, il plugin YouTube corretto, i <code class="language-plaintext highlighter-rouge">rel="noopener noreferrer"</code> aggiunti dappertutto.</p>

<h2 id="immagini-96-mb-diventati-48">Immagini: 9.6 MB diventati 4.8</h2>

<p>Non avevo mai guardato nemmeno la dimensione delle immagini. <code class="language-plaintext highlighter-rouge">profile.png</code> era 3.1 MB. Tremilacento <em>kilobyte</em> per un avatar che si vede a 300×300. Peggio: lo stesso file, alla stessa risoluzione gigantesca, era usato come <code class="language-plaintext highlighter-rouge">og:image</code> per <em>ogni</em> anteprima social. C’era anche <code class="language-plaintext highlighter-rouge">avatar_flv.png</code> da 2.3 MB nella cartella, non referenziato da nessuna parte da chissà quando. Con <code class="language-plaintext highlighter-rouge">imagemagick</code> e <code class="language-plaintext highlighter-rouge">cwebp</code> ho generato <code class="language-plaintext highlighter-rouge">profile-300.webp</code> (16 KB), <code class="language-plaintext highlighter-rouge">profile-600.webp</code> (38 KB) per il retina, e <code class="language-plaintext highlighter-rouge">profile-og.jpg</code> (297 KB) per le anteprime social. Il layout home ora usa un <code class="language-plaintext highlighter-rouge">&lt;picture&gt;</code> con <code class="language-plaintext highlighter-rouge">srcset</code> 1x/2x. Risultato: la cartella <code class="language-plaintext highlighter-rouge">assets/img</code> è passata da 9.6 MB a 4.8 MB, e l’avatar in homepage scarica oggi 16 KB invece di 3.1 MB. Una differenza di duecento volte.</p>

<h2 id="cookie-banner-e-disqus-su-richiesta">Cookie banner e Disqus su richiesta</h2>

<p>La cookie bar che usavo era CookieConsent v3.0.3, libreria abbandonata dal 2018, caricata via protocollo <code class="language-plaintext highlighter-rouge">//</code> (deprecato). L’ho sostituita con <code class="language-plaintext highlighter-rouge">vanilla-cookieconsent</code> v3 di orestbida — moderna, leggera, in italiano. Ma il vero cambiamento è un altro: GoatCounter (le mie statistiche) non setta cookie, e Disqus ora è caricato in <em>lazy load</em> solo quando l’utente accetta esplicitamente la categoria “commenti”. Sui post compare un bottone “Mostra commenti” che, se il consenso non c’è, apre il modal preferenze invece di caricare lo script. Niente cookie di tracciamento finché qualcuno non li chiede, di fatto.</p>

<h2 id="responsive-la-vera-vergogna">Responsive: la vera vergogna</h2>

<p>Il tema, nato in epoca pre-mobile, era pieno di <code class="language-plaintext highlighter-rouge">width: 1000px</code> hardcoded. Su un telefono compariva la scrollbar orizzontale e bisognava zoomare. Ho convertito tutti i container fissi (<code class="language-plaintext highlighter-rouge">.ortalaAna</code>, <code class="language-plaintext highlighter-rouge">.programcerceve</code>, <code class="language-plaintext highlighter-rouge">.iletisim</code>, eccetera) in <code class="language-plaintext highlighter-rouge">max-width</code> con <code class="language-plaintext highlighter-rouge">width: 100%</code>, ho aggiunto un <code class="language-plaintext highlighter-rouge">box-sizing: border-box</code> globale, ho fatto scalare i font con <code class="language-plaintext highlighter-rouge">clamp()</code> invece dei pixel fissi, e ho introdotto due breakpoint nuovi a 768 e 480 pixel. La griglia dei progetti diventa due colonne sotto i 768, una sola sotto i 480. Le sidebar collassano sotto al contenuto. C’è anche un blocco <code class="language-plaintext highlighter-rouge">@media (prefers-reduced-motion: reduce)</code> che disabilita tutte le animazioni e i blur per chi ha quella preferenza nelle impostazioni del sistema operativo.</p>

<h2 id="la-pulizia-semantica">La pulizia semantica</h2>

<p>Il tema l’avevo preso da un autore turco e mi ero portato dietro le sue classi: <code class="language-plaintext highlighter-rouge">.yazi</code>, <code class="language-plaintext highlighter-rouge">.yazibilgisi</code>, <code class="language-plaintext highlighter-rouge">.programcerceve</code>, <code class="language-plaintext highlighter-rouge">.urunResmi</code>, <code class="language-plaintext highlighter-rouge">.menuMobil</code>. Funzionavano, ma aprire i DevTools e leggere <code class="language-plaintext highlighter-rouge">&lt;div class="programcerceve"&gt;</code> era straniante. In una passata di rinomina massiva ho riscritto tutto in nomi semantici inglesi: <code class="language-plaintext highlighter-rouge">.post</code>, <code class="language-plaintext highlighter-rouge">.post-meta</code>, <code class="language-plaintext highlighter-rouge">.project-frame</code>, <code class="language-plaintext highlighter-rouge">.product-image</code>, <code class="language-plaintext highlighter-rouge">.menu-drawer</code>. Trentotto classi rinominate in modo coordinato attraverso layout, SCSS e JavaScript, con boundary regex per non rompere prefissi. E il finale: la stringa <code class="language-plaintext highlighter-rouge">{{ page.date | date_to_string }} tarihinde yayınlandı.</code> — era turco da sempre, “pubblicato in data X” — è diventata <code class="language-plaintext highlighter-rouge">Pubblicato il {% include date-it.html %}</code> con un piccolo include che traduce il mese in italiano. Quindi non più “01 May 2026”, ma “1 maggio 2026”. Otto anni dopo.</p>

<h2 id="cosa-resta">Cosa resta</h2>

<p>Niente di urgente. Le pulizie strutturali sono fatte, il sito è leggero, responsive, accessibile, in italiano, con tutti i bug che mi portavo dietro silenziosamente sistemati. Restano le cose minori: le immagini dei post più vecchi che si potrebbero ottimizzare, qualche <code class="language-plaintext highlighter-rouge">@font-face</code> che si potrebbe restringere a subset latino. Cose che si fanno se si ha voglia, non perché serve.</p>

<p>La parte che mi ha colpito di più non è quanto codice è stato scritto — è quanto è stato <em>eliminato</em>. Variabili SCSS morte, plugin che non chiamavo, librerie obsolete, file di asset abbandonati, classi turche, inline duplicati, link rotti a domini scomparsi. Quasi tutto questo lavoro è stato sottrarre, non aggiungere. E quel tipo di lavoro è quello che, da soli, di solito non si fa mai.</p>]]></content><author><name></name></author><category term="post" /><category term="ai" /><category term="jekyll" /><category term="CSS" /><summary type="html"><![CDATA[Con Claude Code rilevati tanti bug e aggiornato mille cose senza scrivere direttamente una sola linea di codice]]></summary></entry><entry><title type="html">Un mese con Claude</title><link href="https://www.francescolavella.it/mese-con-claude/" rel="alternate" type="text/html" title="Un mese con Claude" /><published>2026-03-28T00:00:00+00:00</published><updated>2026-03-28T00:00:00+00:00</updated><id>https://www.francescolavella.it/mese-con-claude</id><content type="html" xml:base="https://www.francescolavella.it/mese-con-claude/"><![CDATA[<p>Nelle ultime settimane ho lavorato su cinque progetti molto diversi tra loro, quasi tutti con l’aiuto attivo di Claude. Non come suggeritore di snippet, non come motore di ricerca glorificato — ma come qualcuno con cui ragionare ad alta voce, iterare, imprecare quando qualcosa non torna, e ricominciare.</p>

<p>Prima di raccontare i singoli progetti, voglio dire una cosa sull’approccio, perché è cambiato qualcosa nel modo in cui lavoro.</p>

<p>Usare un AI come collaboratore tecnico non significa delegare. Significa avere sempre qualcuno con cui fare il punto. Il vantaggio non è la velocità — anche se quella c’è — ma la possibilità di non restare bloccato. Quando un problema diventa opaco, lo spiego ad alta voce e quasi sempre nel farlo capisco già dove guardare. Claude accelera quel processo: ascolta, risponde in modo contestuale, non parte da zero ogni volta se lo tieni aggiornato. Non è un oracolo. Sbaglia, propone soluzioni che non si compilano, a volte si incarta su dettagli che non esistono. Ma è il miglior interlocutore tecnico che ho avuto in anni, e questo conta.</p>

<hr />

<h2 id="blink-la-rete-lan-aziendale-da-veri-professionisti">BLINK: la rete LAN aziendale da veri professionisti</h2>

<p>Nella mia nuova sede Blink era necessario installare una “Rete con la R maiuscola”. Ho deciso di progettarlo dall’inizio: MikroTik come router centrale, uno switch managed, subnet separate, DHCP con assegnazioni statiche per i dispositivi fissi, e WireGuard per la VPN.</p>

<p>La parte che mi ha tenuto impegnato di più è stata la configurazione WireGuard lato MikroTik. RouterOS gestisce WireGuard in modo leggermente diverso rispetto a una macchina Linux standard, e la documentazione ufficiale è completa ma non sempre immediata da tradurre in pratica. Ho lavorato molto sulla segmentazione delle route e su cosa doveva passare nel tunnel e cosa no.</p>

<p>Cosa non ha funzionato subito: il routing split. Pensavo fosse banale definire quali traffici instradare via VPN e quali tenere locali. Non lo era. Ci sono voluti diversi cicli di test prima di avere un comportamento stabile e prevedibile. Claude è stato utile soprattutto nel diagnosticare i casi limite — traffico che spariva silenziosamente invece di fallire rumorosamente.</p>

<p>Quello che ho imparato: una rete fatta bene richiede di tenere in testa tre livelli contemporaneamente (fisico, logico, applicativo). Quando perdi il filo tra i tre, vai nel panico. Avere qualcuno con cui ricostituire il filo è stato utile quanto gli strumenti di debug.</p>

<hr />

<h2 id="signflow-digital-signage-self-hosted-da-zero">SignFlow: digital signage self-hosted da zero</h2>

<p>Questo è stato il progetto più ambizioso del periodo. Ho costruito una piattaforma di digital signage completamente da zero, senza framework: PHP 8.2 puro, MariaDB, JavaScript vanilla, Apache con mod_rewrite, deploy su Host remoto.</p>

<p>L’idea era semplice: uno schermo remoto che mostra contenuti gestiti da una dashboard web. La realtà era molto meno semplice.</p>

<p><strong>L’autenticazione JWT senza librerie.</strong> Ho scelto di implementare JWT a mano — non per masochismo, ma per capire cosa stavo firmando. È stato istruttivo e ha richiesto attenzione ai dettagli: encoding Base64Url, HMAC-SHA256, gestione della scadenza, validazione rigorosa dei claim. Claude ha tenuto il pacing su tutti e tre i layer (generazione, verifica, refresh) evitando che perdessi il filo tra le parti.</p>

<p><strong>Il sistema di pairing.</strong> Ogni TV si registra con un codice a 6 cifre che scade. Sembra semplice, ma c’era da gestire la race condition tra la richiesta di pairing e la conferma dal server, lo stato del player durante l’attesa, e il comportamento in caso di codice scaduto o già usato. Abbiamo iterato parecchio su questa parte.</p>

<p><strong>SELinux su Fedora.</strong> Questo merita una nota a parte. Il deploy su Fedora con SELinux abilitato è stato un muro. Apache non riusciva a leggere certi file, scrivere in certi path, fare reverse proxy verso socket — tutto silenzioso, senza errori chiari nel log Apache. La diagnostica con <code class="language-plaintext highlighter-rouge">audit2why</code> e <code class="language-plaintext highlighter-rouge">ausearch</code> è diventata una routine quotidiana. Claude conosceva bene il contesto SELinux e ha aiutato a identificare i contesti corretti senza ricorrere a <code class="language-plaintext highlighter-rouge">setenforce 0</code>, che sarebbe stata la resa.</p>

<p><strong>Cosa non ha funzionato subito:</strong> il player HTML5 con fallback offline. La logica era: se il server è irraggiungibile, usa l’ultima playlist scaricata. Sembrava lineare. In pratica, la gestione del Service Worker, il caching delle risorse media e la sincronizzazione allo startup hanno richiesto molto più lavoro del previsto. Qualcosa funzionava nel browser di sviluppo e si rompeva sul Server. Debugging remoto su hardware embedded con risorse limitate è una categoria di dolore a sé.</p>

<p><strong>Cosa ho imparato:</strong> zero framework non significa zero struttura. Significa che la struttura devi darla tu, e se non la dai con attenzione, il codice diventa rapidamente ingestibile. Ho sviluppato convenzioni molto precise per routing, response format e gestione degli errori — cose che un framework impone di default. Farlo manualmente ti fa capire perché esistono i framework.</p>

<hr />

<h2 id="signflow-player-android">SignFlow Player Android</h2>

<p>L’app Android è ancora in lavorazione, ma la base c’è: Kotlin, Media3/ExoPlayer per la riproduzione, Coil per le immagini, Retrofit per la comunicazione con il server.</p>

<p>La parte più interessante è il kiosk mode. Un’app di signage deve resistere all’utente: niente back, niente home, niente notifiche che compaiono sopra il contenuto. Android ha meccanismi per questo (<code class="language-plaintext highlighter-rouge">DevicePolicyManager</code>, lock task mode) ma richiedono di essere il Device Owner dell’apparecchio, cosa che si configura una volta sola al provisioning del dispositivo.</p>

<p>Quello che non ha funzionato subito: la sincronizzazione tra ExoPlayer e la logica della playlist. ExoPlayer gestisce bene le code di media, ma quando la playlist cambia dinamicamente (nuovo contenuto dal server, elemento rimosso, cambio di ordine), la transizione deve essere pulita. Ho trovato diversi edge case in cui il player rimaneva bloccato sull’elemento precedente o saltava un elemento corretto.</p>

<p>Quello che ho imparato: Android ha una quantità enorme di API, molte deprecate e sostituite da alternative più recenti. Muoversi nella documentazione richiede di capire in quale “era” si trova ciascuna API. Claude è stato utile nell’orientarsi tra le versioni e capire cosa usare nel 2025.</p>

<hr />

<h2 id="migrazione-gnome-su-fedora-43">Migrazione GNOME su Fedora 43</h2>

<p>Avevo KDE come desktop e mi trovavo bene, ma ho deciso di passare a GNOME che lo trovo molto più moderno. Non una migrazione drammatica, ma qualcosa che ha richiesto attenzione perché avevo configurazioni specifiche, estensioni, shortcut personalizzati.</p>

<p>Il punto interessante è stato capire cosa sopravvive a una migrazione KDE-to-GNOME e cosa invece è legato alla versione specifica. Alcuni file di configurazione in <code class="language-plaintext highlighter-rouge">~/.config/</code> si trasferiscono direttamente; altri (in particolare le estensioni) dipendono dalla versione di GNOME Shell e possono rompere silenziosamente.</p>

<p>Non è stato il progetto più complicato del mese, ma è stato un buon esempio di come Claude aiuta anche nei task di routine: non facendo le cose al posto tuo, ma ricordandoti i pezzi che avresti dimenticato (le keybindings custom, la configurazione di mimeapps, le impostazioni GTK).</p>

<hr />

<h2 id="sito-jekyll-su-github-pages">Sito Jekyll su GitHub Pages</h2>

<p>Questo stesso sito. Ho rimesso mano all’ambiente di sviluppo locale dopo mesi di inattività, e Ruby non aspettava che io tornassi.</p>

<p>Il problema classico: dipendenze native che non compilavano. <code class="language-plaintext highlighter-rouge">zlib</code>, <code class="language-plaintext highlighter-rouge">libyaml</code>, <code class="language-plaintext highlighter-rouge">libffi</code> — tutte librerie che Jekyll richiede indirettamente, tutte con header che il sistema non trovava nel percorso giusto. Su Fedora, con la versione di Ruby gestita da <code class="language-plaintext highlighter-rouge">rbenv</code>, la sequenza corretta di flag di compilazione non è ovvia.</p>

<p>Ho anche integrato Goatcounter come sistema di analytics. È leggero, self-hostable, rispettoso della privacy, e non richiede cookie banner. L’integrazione in Jekyll è stata semplice — un frammento di JavaScript nel layout base — ma volevo capire esattamente cosa traccia e come, prima di aggiungerlo.</p>

<p>Quello che ho imparato: mantenere un ambiente Jekyll attivo richiede attenzione periodica. Non è un “set and forget”. Le dipendenze Ruby hanno un loro ciclo di vita, e ignorarle per sei mesi significa quasi certamente rompere qualcosa.</p>

<hr />

<h2 id="quello-che-rimane">Quello che rimane</h2>

<p>Guardando indietro a queste settimane, quello che colpisce non è la quantità di cose fatte — è la varietà. Reti, backend PHP, Android, desktop Linux, Ruby gems: domini diversi, problemi diversi, strumenti diversi.</p>

<p>In passato, questa varietà sarebbe stata un collo di bottiglia. Passare da MikroTik a SELinux a Kotlin in pochi giorni richiedeva ogni volta un riscaldamento cognitivo lungo. Con Claude, quel riscaldamento è più corto. Non perché lui sappia tutto — sbaglia spesso sui dettagli specifici di versione, a volte alucina API che non esistono, a volte propone soluzioni che funzionano in teoria ma hanno problemi pratici ovvi. Ma sa tenere il contesto, fare le domande giuste, e aiutarti a non perdere il filo.</p>

<p>I limiti reali sono due. Il primo: Claude non può testare. Può ragionare su un problema, proporre una soluzione, identificare edge case — ma non può vedere cosa succede quando il codice gira sul Server remoto con quella specifica versione di PHP e SELinux configurato in quel modo. Il testing rimane completamente tuo. Il secondo: il contesto finisce. Conversazioni lunghe su progetti complessi richiedono gestione attiva — ricapitolare lo stato, riorientare la discussione. Non è un difetto fatale, ma è un lavoro che va fatto.</p>

<p>Quello che rimane da fare: SignFlow Player Android ha ancora diversi edge case aperti. La rete BLINK funziona ma voglio aggiungere monitoring. E questo sito ha bisogno di più post.</p>

<hr />

<p><strong>Generated with the support of AI</strong></p>

<p><strong>Licenza d’uso</strong>
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">© CC BY-NC-SA</a></p>]]></content><author><name></name></author><category term="riflessioni" /><category term="post" /><category term="ai" /><category term="linux" /><category term="networking" /><category term="php" /><category term="android" /><category term="jekyll" /><category term="signage" /><summary type="html"><![CDATA[Rete LAN, digital signage, Android, GNOME, Jekyll: cinque progetti in poche settimane. Un resoconto onesto su cosa significa avere un AI come collaboratore tecnico reale.]]></summary></entry><entry><title type="html">JARVIS 2.0: Server Domestico</title><link href="https://www.francescolavella.it/upgrade-fedora/" rel="alternate" type="text/html" title="JARVIS 2.0: Server Domestico" /><published>2025-12-24T00:00:00+00:00</published><updated>2025-12-24T00:00:00+00:00</updated><id>https://www.francescolavella.it/upgrade-fedora</id><content type="html" xml:base="https://www.francescolavella.it/upgrade-fedora/"><![CDATA[<p>Nel precedente articolo abbiamo visto i primi passi della nascita di <strong>JARVIS</strong>, il mio server domestico. Ma come ogni buon progetto, “basta che funzioni” non era abbastanza. Volevo sicurezza, performance e automazione.</p>

<p>Oggi vi racconto come ho trasformato una semplice workstation in una fortezza digitale, gestendo storage, streaming 4K e accesso VPN remoto, il tutto su base <strong>Fedora Linux</strong>.</p>

<h3 id="lo-storage-la-filosofia-keep-it-simple"><strong>Lo Storage: La filosofia “Keep It Simple”</strong></h3>

<p>Siamo partiti con una situazione complessa (RAID degradati), e siamo atterrati sulla soluzione più robusta: JBOD (Just a Bunch Of Disks). Invece di affidarci a controller RAID software instabili, abbiamo montato i 4 dischi singolarmente tramite <code class="language-plaintext highlighter-rouge">/etc/fstab</code>.</p>

<ul>
  <li>
    <p><strong>Vantaggio</strong>: Se un disco muore, perdo solo quei dati, non l’intero array.</p>
  </li>
  <li>
    <p><strong>Organizzazione</strong>: Ogni disco ha uno scopo preciso (Film, Serie TV, Dati, Backup), montati in modo pulito sotto <code class="language-plaintext highlighter-rouge">/mnt</code>.</p>
  </li>
</ul>

<h3 id="il-cuore-multimediale-jellyfin-su-podman"><strong>Il Cuore Multimediale: Jellyfin su Podman</strong></h3>

<p>Per lo streaming dei media non ho installato software “sporcando” il sistema operativo. Ho scelto <strong>Podman</strong> (l’alternativa sicura a Docker di RedHat).</p>

<p><strong>La sfida della Transcodifica (HEVC/H.265)</strong></p>

<p>Il problema principale era la riproduzione di file moderni (MKV in H.265). Fedora, essendo open-source puro, non include i codec proprietari di default. <strong>La soluzione:</strong></p>

<ol>
  <li>
    <p>Abilitazione dei repository <strong>RPM Fusion</strong>.</p>
  </li>
  <li>
    <p>Installazione tramite <code class="language-plaintext highlighter-rouge">dnf5</code> dei gruppi <code class="language-plaintext highlighter-rouge">multimedia</code> e <code class="language-plaintext highlighter-rouge">sound-and-video</code>.</p>
  </li>
  <li>
    <p>Aggiunta delle librerie <code class="language-plaintext highlighter-rouge">ffmpeg-libs</code> e <code class="language-plaintext highlighter-rouge">x265</code>.</p>
  </li>
</ol>

<p>Ora JARVIS macina flussi 4K senza incertezze, e grazie alla configurazione di Podman con flag <code class="language-plaintext highlighter-rouge">--restart=always</code> e il servizio <code class="language-plaintext highlighter-rouge">podman-restart</code>, il media server torna online da solo anche dopo un blackout.</p>

<h3 id="la-fortezza-digitale-firewalld-e-zone"><strong>La Fortezza Digitale: Firewalld e Zone</strong></h3>

<p>Qui è dove JARVIS ha fatto il salto di qualità. Invece di un firewall piatto (“apri tutto o chiudi tutto”), abbiamo implementato una strategia a <strong>Zone</strong>.</p>

<p><strong>Zona 1: La Casa (Rete Fisica <code class="language-plaintext highlighter-rouge">enp2s0</code>)</strong></p>

<p>Sulla rete locale, la sicurezza è massima. Abbiamo rimosso il range di porte 1025-65535 (aperto di default su Fedora Workstation) applicando un approccio <strong>Whitelist</strong>:</p>

<ul>
  <li>
    <p><strong>Bloccato</strong>: Tutto.</p>
  </li>
  <li>
    <p><strong>Permesso</strong>: Solo SSH (22), Samba, Jellyfin (8096) e Torrent (2767 TCP/UDP).</p>
  </li>
</ul>

<p><strong>Zona 2: L’Ufficio (VPN <code class="language-plaintext highlighter-rouge">sintabVPN</code>)</strong></p>

<p>Il server è collegato all’ufficio tramite una VPN gestita da una Raspberry Pi. Abbiamo spostato l’interfaccia virtuale sintabVPN nella zona <strong>Trusted</strong>.</p>

<p><strong>Risultato</strong>: Chi entra dalla VPN è considerato “fidato” e ha accesso completo ai servizi senza dover aprire porte extra sul firewall pubblico.</p>

<h3 id="networking-e-identità"><strong>Networking e Identità</strong></h3>

<p>Basta ricordare indirizzi IP come <code class="language-plaintext highlighter-rouge">192.168.1.100</code>.</p>

<ul>
  <li>
    <p><strong>Hostname</strong>: Il server risponde al nome <code class="language-plaintext highlighter-rouge">jarvis</code>.</p>
  </li>
  <li>
    <p><strong>Risoluzione Nomi</strong>: In casa sfruttiamo mDNS (<code class="language-plaintext highlighter-rouge">jarvis.local</code>), mentre per i colleghi in VPN abbiamo configurato i file hosts per un accesso trasparente alle cartelle condivise (<code class="language-plaintext highlighter-rouge">\\jarvis</code>).</p>
  </li>
</ul>

<p>Inoltre, per i <strong>Torrent</strong>, abbiamo configurato non solo il firewall di Fedora, ma anche il Port Forwarding sul Router, garantendo la “connettività” completa ai peer per download alla massima velocità.</p>

<h3 id="manutenzione-il-tagliando-mensile"><strong>Manutenzione: Il “Tagliando” Mensile</strong></h3>

<p>Un server deve restare pulito. Invece di lanciare comandi a caso, ho creato uno script automatizzato (<code class="language-plaintext highlighter-rouge">tagliando.sh</code>) che esegue:</p>

<ol>
  <li>Aggiornamento sistema (<code class="language-plaintext highlighter-rouge">dnf5 update</code>).</li>
  <li>Pulizia cache e container orfani (<code class="language-plaintext highlighter-rouge">podman system prune</code>).</li>
  <li>Check-up salute dei dischi (<code class="language-plaintext highlighter-rouge">smartctl</code>).</li>
  <li>Ottimizzazione performance (<code class="language-plaintext highlighter-rouge">tuned</code> impostato su throughput-performance).</li>
</ol>

<h3 id="conclusione"><strong>Conclusione</strong></h3>

<p>JARVIS non è più un semplice PC assemblato. È un server Linux moderno, sicuro e resiliente. Gestisce i dati aziendali via VPN in modo trasparente e l’intrattenimento domestico senza transcodifiche fallite.</p>

<p>La lezione imparata? Pellicola via il superfluo, isola i servizi nei container e usa il firewall in modo intelligente.</p>

<p><strong>Generated with the support of AI</strong></p>

<p><strong>Licenza d’uso</strong>
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">© CC BY-NC-SA</a></p>]]></content><author><name></name></author><category term="post" /><category term="linux" /><category term="fedora" /><summary type="html"><![CDATA[JARVIS 2.0: Server Domestico]]></summary></entry><entry><title type="html">Media Server con Fedora</title><link href="https://www.francescolavella.it/guida-fedora/" rel="alternate" type="text/html" title="Media Server con Fedora" /><published>2025-12-20T00:00:00+00:00</published><updated>2025-12-20T00:00:00+00:00</updated><id>https://www.francescolavella.it/guida-fedora</id><content type="html" xml:base="https://www.francescolavella.it/guida-fedora/"><![CDATA[<h1 id="dallinstallazione-di-fedora-alla-gestione-di-onedrive-e-jellyfin-con-podman-ecco-come-ho-trasformato-il-mio-nuovo-pc-ricondizionato-in-una-centrale-multimediale-sicura-ed-efficiente">Dall’installazione di Fedora alla gestione di OneDrive e Jellyfin con Podman. Ecco come ho trasformato il mio nuovo PC (ricondizionato) in una centrale multimediale sicura ed efficiente</h1>
<p><strong>Introduzione</strong></p>

<p>Di recente ho deciso di prendere il controllo completo dei miei dati e del mio intrattenimento domestico. L’obiettivo? Creare un sistema che fosse stabile come una roccia, flessibile e capace di gestire tutto: Workstation per ufficio, backup su OneDrive, streaming di film in 4K, recuperando vecchi hard disk da sistemi RAID precedenti.</p>

<p>La mia scelta è ricaduta su Fedora Linux con KDE Plasma. Perché? Perché offre il bilanciamento perfetto tra tecnologie all’avanguardia (BTRFS, Pipewire, Wayland) e una buona stabilità</p>

<p>In questa guida condivido i passaggi chiave della mia configurazione, sperando possa servire da “faro” per chi vuole intraprendere lo stesso viaggio.</p>

<p><strong>Le Fondamenta: Codec e Strumenti Base</strong></p>

<p>Appena installata Fedora (operazione filata liscia senza intoppi e senza sbattimenti), la prima cosa da fare è “sbloccarne” il potenziale multimediale. Fedora sposa la filosofia open source pura, quindi per leggere formati proprietari (come H.265 o MP4) serve un piccolo intervento.</p>

<p>Ho abilitato i repository RPM Fusion e installato la versione completa di FFmpeg, fondamentale per la transcodifica video:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo dnf swap ffmpeg-free ffmpeg --allowerasing
sudo dnf group upgrade multimedia --setop="install_weak_deps=False" --exclude=PackageKit-gstreamer-plugin
</code></pre></div></div>

<p>Inoltre, ho installato KDE Connect, uno strumento che consiglio a tutti: permette di collegare il telefono Android al PC per controllare il mouse dal divano, mettere in pausa i film quando squilla il telefono e trasferire file al volo.</p>

<p><strong>Il Cloud Integrato: OneDrive come se fosse una USB</strong></p>

<p>Uno dei punti critici su Linux è l’assenza di un client ufficiale OneDrive. Ho risolto brillantemente usando Rclone, un tool a riga di comando potentissimo.</p>

<p>Invece di sincronizzare i file (occupando spazio sul disco), ho configurato un “Mount”. In pratica, Fedora vede il cloud come se fosse una chiavetta USB sempre attaccata.</p>

<p>Per rendere tutto automatico all’avvio senza dover aprire il terminale, ho creato un servizio Systemd personalizzato:
Ini, TOML</p>

<p>Esempio del mio servizio <code class="language-plaintext highlighter-rouge">~/.config/systemd/user/rclone-onedrive.service</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Unit
Description=OneDrive (Rclone)
AssertPathIsDirectory=%h/Cloud
After=network-online.target

Service
Type=notify
ExecStart=/usr/bin/rclone mount onedrive: %h/Cloud --vfs-cache-mode full --no-modtime
ExecStop=/usr/bin/fusermount -u %h/Cloud
Restart=on-failure

Install
WantedBy=default.target
</code></pre></div></div>

<p>Risultato? Accendo il PC e i miei file cloud sono già lì nella cartella “Cloud”.</p>

<p><strong>Jellyfin e la magia di Podman</strong></p>

<p>Per il media server (l’alternativa open source a Plex), non ho “sporcato” il sistema installando pacchetti a caso. Ho usato Podman.</p>

<p>Podman è l’alternativa a Docker nativa di Fedora: è più sicuro (non richiede permessi di root) e si integra perfettamente col sistema.</p>

<p>Ecco il comando che ho usato per lanciare il server, abilitando l’accelerazione hardware <code class="language-plaintext highlighter-rouge">(/dev/dri)</code> per non sforzare la CPU durante i film:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman run -d \
 --name jellyfin \
 --label "io.containers.autoupdate=registry" \
 --security-opt label=disable \
 -p 8096:8096 \
 -v ~/.config/jellyfin:/config \
 -v ~/.cache/jellyfin:/cache \
 -v /mnt/raid_jarvis:/media/jarvis \
 --device /dev/dri:/dev/dri \
 docker.io/jellyfin/jellyfin:latest
</code></pre></div></div>
<p>Nota tecnica: L’opzione <code class="language-plaintext highlighter-rouge">--security-opt label=disable</code> è stata fondamentale per permettere a Jellyfin di leggere i file dai miei hard disk recuperati da vecchi NAS, aggirando le restrizioni rigide di SELinux.</p>

<p><strong>Gestione Storage: Recupero RAID e Futuro</strong></p>

<p>La parte più delicata è stata gestire 4 hard disk SATA, alcuni provenienti da vecchi sistemi RAID (mdadm). Linux è stato eccezionale nel riconoscere automaticamente i vecchi array RAID 1, permettendomi di montarli e recuperare i dati senza perdere un bit.</p>

<p>Il mio piano per il futuro? Abbandonare il RAID complesso per una configurazione JBOD (Dischi indipendenti) in EXT4. Più semplice, meno rischi di rottura software, e se un disco muore, perdo solo quei dati e non tutto l’array.</p>

<p><strong>Sicurezza ed Efficienza Energetica</strong></p>

<p>Un server acceso h24 deve consumare poco ed essere sicuro.</p>

<p>Backup del Sistema: Ho configurato Timeshift (in modalità RSYNC). Fa delle “foto” al sistema operativo. Se un aggiornamento rompe qualcosa, posso tornare indietro nel tempo in 5 minuti.</p>

<p>Risparmio Energetico: Visto che il PC fa da server, ho usato <code class="language-plaintext highlighter-rouge">powerprofilesctl set power-saver</code> per calmare la CPU e hdparm per spegnere i dischi meccanici dopo 20 minuti di inattività.</p>

<p><strong>Conclusione</strong></p>

<p>Questa esperienza mi ha confermato che Linux oggi non è solo per smanettoni, ma è una piattaforma incredibilmente potente per gestire la propria vita digitale. Con Fedora ho un sistema che è mio al 100%, privato, veloce e costruito esattamente sulle mie esigenze.</p>

<p><strong>Generated with the support of AI</strong></p>

<p><strong>Licenza d’uso</strong>
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">© CC BY-NC-SA</a></p>]]></content><author><name></name></author><category term="post" /><category term="linux" /><category term="fedora" /><summary type="html"><![CDATA[Media Server con Fedora]]></summary></entry><entry><title type="html">Installazione Jekyll su WSL</title><link href="https://www.francescolavella.it/guida-install-jekyll/" rel="alternate" type="text/html" title="Installazione Jekyll su WSL" /><published>2025-09-19T00:00:00+00:00</published><updated>2025-09-19T00:00:00+00:00</updated><id>https://www.francescolavella.it/guida-install-jekyll</id><content type="html" xml:base="https://www.francescolavella.it/guida-install-jekyll/"><![CDATA[<h1 id="guida-passo-passo-per-installare-jekyll-e-gestire-il-nostro-sito"><strong>Guida Passo Passo per installare Jekyll e gestire il nostro sito</strong></h1>

<p>Anche se questo sito è rimasto dormiente per un pò, grazie all’azzeccatissima scelta di utilizzare jekyll come motore per scrivere questo sito, con pochi passaggi ho di nuovo tutto bello pronto e aggiornato all’ultima versione</p>

<p>Ma prima di aggiornare questo post ho dovuto riconfigurare jekyll sul mio pc, sincronizzare i repo su git e via…</p>

<p>Raccolgo in questa guida tutti i passaggi passo passo, da zero per un sistema funzionante su WSL Ubuntu</p>

<h3 id="installeremo">Installeremo</h3>
<ol>
  <li>Ruby 3.4.6</li>
  <li>Jekyll 4.4</li>
  <li>imagemagick (per me è necessario perchè ho una gallery)</li>
  <li>Git</li>
</ol>

<h3 id="ruby">Ruby</h3>

<p>Installazione con rbenv (consigliato)</p>

<p>Aggiorna i pacchetti e installa le dipendenze</p>

<p>Apri il tuo terminale WSL e esegui i seguenti comandi per aggiornare la lista dei pacchetti e installare le librerie necessarie per la compilazione di Ruby</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt update
sudo apt install -y build-essential libssl-dev libreadline-dev zlib1g-dev libffi-dev libyaml-dev
</code></pre></div></div>

<p>Installa rbenv</p>

<p>Clona il repository di rbenv</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/rbenv/rbenv.git ~/.rbenv
</code></pre></div></div>

<p>Inizializza rbenv nel tuo terminale (questo aggiungerà le righe necessarie al tuo file .bashrc o .zshrc)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo 'export PATH="$HOME/.rbenv/bin:$PATH"' &gt;&gt; ~/.bashrc
echo 'eval "$(rbenv init -)"' &gt;&gt; ~/.bashrc
source ~/.bashrc
</code></pre></div></div>

<p>Installa il plugin ruby-build
Questo plugin permette a rbenv di scaricare e compilare Ruby</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
</code></pre></div></div>

<p>Installa Ruby 3.4.6</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rbenv install 3.4.6
</code></pre></div></div>

<p>Questo comando scaricherà e compilerà Ruby, il che potrebbe richiedere alcuni minuti.</p>

<p>Verifica l’installazione</p>

<p>Controlla che Ruby sia stato installato correttamente e che sia la versione desiderata:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ruby -v
</code></pre></div></div>

<h3 id="jekyll">Jekyll</h3>
<p>Installa Bundler</p>

<p>È utile installare subito Bundler, il gestore di gemme per Ruby</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem install bundler
rbenv rehash
gem update --system
gem install bundler jekyll
rbenv rehash
jekyll -v
</code></pre></div></div>

<h3 id="sito-jekyll-già-installato">Sito jekyll già installato</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle update
bundle exec jekyll serve
</code></pre></div></div>

<p>Anteprima</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://127.0.0.1:4000/
</code></pre></div></div>

<h3 id="github">github</h3>

<p>Aggiorna e installa Git (in WSL)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt update &amp;&amp; sudo apt install -y git openssh-client
</code></pre></div></div>

<p>Configura Git (nome/email e opzioni utili)</p>

<p>Sostituisci con i tuoi dati GitHub.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config --global user.name "Nome Cognome"
git config --global user.email "la-tua-email-collegata-a-github@example.com"
git config --global init.defaultBranch main
git config --global pull.rebase false
</code></pre></div></div>

<p>Genera una chiave SSH in WSL (salta questo passaggio se hai già una tua chiave)</p>

<p>Consigliato per evitare token/password ogni volta.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen -t ed25519 -C "la-tua-email-collegata-a-github@example.com"
</code></pre></div></div>

<p>Premi Invio per accettare ~/.ssh/id_ed25519 e (facoltativo) imposta una passphrase</p>

<p>Avvia l’agent e carica la chiave</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
</code></pre></div></div>

<p>Aggiungi la chiave pubblica al tuo account GitHub</p>

<p>Copia la chiave</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat ~/.ssh/id_ed25519.pub
</code></pre></div></div>

<p>Vai su GitHub → Settings → SSH and GPG keys → New SSH key.</p>

<p>Incolla l’output.</p>

<p>(Se preferisci via CLI, puoi installare gh e fare gh auth login, ma non è necessario.)</p>

<p>Testa la connessione SSH a GitHub</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -T git@github.com
</code></pre></div></div>

<p>Alla prima connessione, rispondi yes. Se vedi un messaggio tipo “Hi <tuo-username>! You've successfully authenticated…”, sei a posto.</tuo-username></p>

<p>Scegli dove mettere il progetto e clona il repo</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p ~/progetti &amp;&amp; cd ~/progetti
git clone git@github.com:tuorepo.git
cd progetti
</code></pre></div></div>

<p>Verifiche rapide</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git remote -v           # deve mostrare l'URL SSH
git status              # stato della working tree
</code></pre></div></div>

<h3 id="aggiornare-i-repo">Aggiornare i repo</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git add -A
git commit -m "Aggiornamenti"
git push origin main
</code></pre></div></div>

<h3 id="alias">Alias</h3>
<p>Se hai il tuo progetto in una cartella Documenti di windows spesso il comando è un pò lungo, per velocizzare la cosa ho impostato un alias, ti mostro come fare</p>

<p>In WSL le directory di Windows sono in /mnt/c/</p>

<p>un comando tipico potrebbe essere cd “/mnt/c/Users/Francesco/Code/repo-git” (è messo tra “ “ perchè in questo modo eventuali spazi presenti nelle directory sono gestiti senza errori)</p>

<p>Utlizziamo gli alias per praticità</p>

<p>Se usi bash (default in WSL):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano ~/.bashrc
</code></pre></div></div>

<p>Aggiungi l’alias in fondo al file</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>alias jekyll='cd "/mnt/c/Users/Francesco/Code/repo-git"'
</code></pre></div></div>

<p>Così il comando sarà jekyll</p>

<p>Ricarica la configurazione</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>source ~/.bashrc   # o ~/.zshrc se usi zsh
</code></pre></div></div>

<p>D’ora in poi, ti basta digitare:</p>

<p>jekyll</p>

<p>e verrai portato direttamente nella cartella del progetto.</p>

<h3 id="github-page">github page</h3>
<p>il build “nativo” di GitHub Pages non supporta Jekyll 4.4 (al momento GitHub Pages usa lo stack github-pages che blocca Jekyll a 3.10.x)</p>

<p>Per usare Jekyll 4.4 devi costruire il sito con GitHub Actions e pubblicare l’output di _site</p>

<p><strong>DNS Github page</strong>
A records,</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153
</code></pre></div></div>

<p>AAAA records</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2606:50c0:8000::153
2606:50c0:8001::153
2606:50c0:8002::153
2606:50c0:8003::153
</code></pre></div></div>

<p>Nel mio caso specifico:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Valore: @   Tipo: A     Valore: 185.199.108.153
Valore: @   Tipo: A     Valore: 185.199.109.153
Valore: @   Tipo: A     Valore: 185.199.110.153
Valore: @   Tipo: A     Valore: 185.199.111.153
Valore: www Tipo: CNAME Valore: francescolv.github.io
</code></pre></div></div>

<p>Ricordi di forzare nel pannello di ghithub HTTPS</p>

<p><strong>Applicativi aggiuntivi che possono tornare utili</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt-get install libmagickwand-dev
</code></pre></div></div>

<p>Github Page Actions non digerisce la gallery con questo metodo, quindi ho riscritto completamente la Gallery utilizzando solo HTML/CSS senza plugin esterni</p>

<p><strong>Licenza d’uso</strong>
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">© CC BY-NC-SA</a></p>]]></content><author><name></name></author><category term="post" /><category term="jekyll" /><summary type="html"><![CDATA[Installazione Jekyll su WSL]]></summary></entry><entry><title type="html">Nuovo anno Nuovo server</title><link href="https://www.francescolavella.it/nuovo-server/" rel="alternate" type="text/html" title="Nuovo anno Nuovo server" /><published>2020-02-15T00:00:00+00:00</published><updated>2020-02-15T00:00:00+00:00</updated><id>https://www.francescolavella.it/nuovo-server</id><content type="html" xml:base="https://www.francescolavella.it/nuovo-server/"><![CDATA[<h1 id="nuovo-anno-nuovo-server"><strong>Nuovo Anno Nuovo Server</strong></h1>

<p>E’ passato veramente tanto tempo dall’ultimo post pubblicato, un pò a causa di impegni professionali, un pò perchè questo sito in jekyll hostato su github aveva qualche problema.</p>

<p>Allora mi sono deciso a traslocare su un server personale ed aggiornare Jekyll all’ultima versione 4.0</p>

<p>Devo dire che la cosa è stata abbastanza semplice avendo già una LAMP pronta, è stato sufficiente trasferire la directory <code class="language-plaintext highlighter-rouge">_site</code> generata con il comando <code class="language-plaintext highlighter-rouge">jekyll build</code> , puntare il virtual host e i DNS al nuovo server ed il gioco è fatto</p>

<p>E visto che la cosa mi è piaciuta, abbiamo deciso di rinnovare anche il sito <a href="https://www.sintab.it">www.sintab.it</a> con jekyll - Presto online</p>

<p>L’unica cosa che mi rimane da capire è come sincronizzare in modo più rapido il sito locale con quello remoto, con git era veramente immediato, con FTP la cosa è un pò più macchinosa. Quando trovo una soluzione interessante ci faccio un nuovo post.</p>

<p><strong>Upgrade</strong>
La soluzione che ho trovato per trasferire i file sul server è attraverso il comando rsync (premesso che io ho una chiave ssh con passphrase):</p>

<p>Per trasferire da locale a remoto</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rsync -aP -e "ssh -i /home/utente/.ssh/chiavessh" _site/ utente@IPSERVER:/home/utente/sitojekyll/
</code></pre></div></div>

<p>Nel server dalla directory sincronizzata con il comando precedente, sincronizzo con la directory presente in /var/www</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rsync -aP sitojekyll/ /var/www/sitojekyll/
</code></pre></div></div>

<p><strong>Licenza d’uso</strong>
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">© CC BY-NC-SA</a></p>]]></content><author><name></name></author><category term="post" /><category term="jekyll" /><summary type="html"><![CDATA[Nuovo anno Nuovo server]]></summary></entry><entry><title type="html">Photo Galley</title><link href="https://www.francescolavella.it/photo-gallery/" rel="alternate" type="text/html" title="Photo Galley" /><published>2019-05-10T00:00:00+00:00</published><updated>2019-05-10T00:00:00+00:00</updated><id>https://www.francescolavella.it/photo-gallery</id><content type="html" xml:base="https://www.francescolavella.it/photo-gallery/"><![CDATA[<h1 id="creare-una-photo-galley-con-jekyll"><strong>Creare una Photo Galley con Jekyll</strong></h1>

<h2 id="obiettivi">Obiettivi</h2>
<p>Creare una gallery per la pubblicazione delle Immagini e la generazione automatica di thumbnails delle foto caricate</p>

<h2 id="descrizione">Descrizione</h2>
<p><strong>Installare su Ubuntu le dipendenze</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install libmagick++-dev
gem install rmagick exifr
</code></pre></div></div>
<p><strong>Installare il plugin</strong> jekyll-gallery-generator
o attraverso</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem install jekyll-gallery-generator
</code></pre></div></div>
<p>o attraverso <code class="language-plaintext highlighter-rouge">gem 'jekyll-gallery-generator'</code> nel file <code class="language-plaintext highlighter-rouge">Gemfile</code></p>

<p>e lanciare il comando <code class="language-plaintext highlighter-rouge">bundle</code></p>

<p>Aggiungere jekyll-gallery-generator nella lista dei plugin in _config.yml:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>plugins:
  - jekyll-gallery-generator
</code></pre></div></div>

<p>Crea una directory photos e al suo interno una directory per ogni gallery</p>

<h2 id="configurazione">Configurazione</h2>
<p>Aggiungere nel file _config.yml</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gallery:
  dir: photos               # Path to the gallery
  symlink: false            # false: copy images into _site. true: create symbolic links (saves disk space)
  title: "Photos"           # Title for gallery index page
  title_prefix: "Photos: "  # Title prefix for gallery pages. Gallery title = title_prefix + gallery_name
  sort_field: "date_time"   # How to sort galleries on the index page.
                            # Possible values are: title, date_time, best_image
  thumbnail_size:
    x: 400                  # max width of thumbnails (in pixels)
    y: 400                  # max height of thumbnails (in pixels)
  
  # The following options are for individual galleries.
  galleries:
    nome_gallery:
      best_image: image.jpg  # The image to show on the gallery index page. Defaults to the last image.
      name: "nome_gallery"
      hidden: true          # Don't show this gallery on the index page. People must guess the URL.
      sort_reverse: true    # Reverse sort images in gallery.
      info:
        desc: "Gallery Description" # Info fields can be used in custom templates.
</code></pre></div></div>

<h2 id="riferimenti">Riferimenti</h2>
<p>per ulteriori informazioni:
<a href="https://github.com/ggreer/jekyll-gallery-generator">https://github.com/ggreer/jekyll-gallery-generator</a></p>

<p><strong>Licenza d’uso</strong>
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">© CC BY-NC-SA</a></p>]]></content><author><name></name></author><category term="Howto" /><category term="post" /><category term="jekyll" /><summary type="html"><![CDATA[Photo Galley]]></summary></entry></feed>