Addio WordPress: il mio blog ora è statico
Qualche tempo fa ho migrato il mio blog, o meglio l’intero sito web, da WordPress alla versione statica che state vedendo in questo momento. Vi racconto come ho fatto e quali soluzioni ho adottato.
Il sito www.emmecilab.net è attivo dal 2008 ed è nato originariamente come un raccoglitore personale di tutti i contenuti legati ai miei studi universitari e il materiale prodotto durante i vari progetti e le attività lavorative.
Più che altro come una sorta di promemoria per ricordarmi tutte le procedure e avere dei tutorial da consultare velocemente all'occorrenza.
In effetti spesso mi capita di dimenticare tutti i dettagli di una procedura complessa con tanti passaggi da fare, oppure la sintassi dettagliata del codice ecc.
Successivamente ho pensato che potesse essere utile condividerlo con gli altri e quindi è nata l'idea del blog che originariamente era basata sul noto cms WordPress.
Premetto che non sono un esperto di WP e che l’articolo non vuole essere assolutamente denigratorio nei suoi confronti o in quelli di qualsiasi altro cms del genere.
Ritengo che sia un'ottima soluzione, ma che abbia bisogno di essere gestita sia attraverso una opportuna configurazione che sfruttando i plugin appositi per le funzionalità che si desidera implementare.
Insomma diciamo che non andrebbe utilizzato out-of-the-box senza nessun tipo di personalizzazione e configurazione anche e soprattutto per motivi di sicurezza.
Quindi ho pensato ad una migrazione verso un sito statico.
Ma di cosa si tratta esattamente?
In parole semplici di un sito fatto da pagine HTML con CSS e codice Javacript.
Può essere scritto da zero oppure generato a partire da una specifica applicazione web che può funzionare in maniera tradizionale, cioè utilizzando un web server, oppure da questa si può generare appunto una versione statica ovvero tutte le pagine HTML complete di fogli di stile ed eventuale codice Javascript che possono essere ospitate presso un qualsiasi provider.
Il "problema" principale di WordPress e di molti altri cms è che occorre utilizzare comunque un web server in grado di supportare PHP (o altri linguaggi) nonchè un database all'interno del quale sono ospitati tutti i contenuti.
Non è tanto un discorso di costi che oggi sono più che abbordabili rispetto al passato; il problema è che affinché questa soluzione funzioni correttamente occorre starci dietro nel senso di aggiornare il cms, non installare tutti i plugin che troviamo in giro, perché spesso non sono aggiornati e ci espongono a rischi per la sicurezza, e soprattutto garantire la protezione e anche l'eventuale scalabilità del database.
Quest'ultimo rappresenta un fattore critico perchè va monitorato costantemente, aggiornato al rilascio di patch di sicurezza e così via.
Ovviamente non è niente di impossibile, esistono milioni di siti basati su questa architettura, ma per i miei scopi era richiesto un eccessivo impegno.
In effetti il mio è solo un blog, non un sito di e-commerce o di altro genere che deve offrire servizi online per cui la soluzione basata su WordPress mi sembrava sovradimensionata, senza contare che un sito statico può essere ospitato dappertutto, a partire dalle GitHub Pages.
Vediamo allora cosa ho fatto.
Talvolta ho trattato Vue.js in ambito front-end. Non ho una conoscenza approfondita dell'argomento visto che sono essenzialmente uno sviluppatore back-end, tuttavia ho cercato un CMS che fosse basato su questo framework così da poter sfruttare le mie conoscenze di base.
Ed ecco Nuxt (https://nuxt.com/).
Sostanzialmente permette di costruire dei siti oltre a disporre di vari componenti con cui si può ad esempio gestire facilmente un blog, che poi è la parte che più mi interessava.
In effetti il mio sito ha delle pagine che illustrano l'attività, i servizi offerti ma la parte più consistente e interessante è rappresentata proprio dal blog.
Per questo motivo avevo la necessità di gestirlo facilmente con una soluzione più flessibile di quella offerta da WordPress.
Ad onor del vero il CMS consente di scrivere gli articoli, di aggiungere degli elementi multimediali, di salvarli e così via ma sempre e comunque con l'appoggio del database.
Con Nuxt i contenuti sono costituiti da pagine in Markdown, un formato molto diffuso per scrivere la documentazione dei progetti online, quindi è stato anche un vantaggio apprendere meglio la sua sintassi per utilizzarla in altri contesti.
Inoltre esiste la possibilità di preparare gli articoli, impaginarli e salvarli all'interno di una cartella di cui parleremo più dettaglio in seguito.
Quindi il primo passo per la migrazione alla nuova piattaforma era quello di recuperare tutti gli articoli già realizzati su WordPress e in effetti l'ho fatto utilizzando il plugin wordpress-export-to-markdown (https://github.com/lonekorean/wordpress-export-to-markdown) che consente di esportare tutto il contenuto degli articoli in formato Markdown così da riutilizzarlo in Nuxt.
Successivamente ho preso un tema su Envato ThemeForest (https://themeforest.net/) e l'ho adattato alle mie esigenze.
E infine ho creato una pipeline su GitHub Actions per automatizzare tutto processo di pubblicazione del sito ad ogni aggiornamento effettuato.
In sostanza sul mio computer ho la copia locale del repository presente su GitHub.
Scrivo i miei articoli, li inserisco all'interno di un'opportuna cartella, carico il codice su GitHub e a questo punto scatta tutta la pipeline di Continuous Integration, che crea la versione statica del sito, la salva su un opportuno branch del repository e poi la carica su Netlify (https://www.netlify.com/).
Ho scelto questo provider per poter utilizzare anche la CDN messa a disposizione.
Del mio dominio ho la la gestione dei DNS per cui l'ho agganciato proprio all'applicazione su Netlify.
Nell'arco di uno o massimo due minuti il sito viene aggiornato e questo mi consente di non preoccuparmi di tutto ciò che riguarda l'infrastruttura e la pubblicazione, così da potermi concentrare sui contenuti e cercare di fare un buon lavoro.
Ora andiamo ad analizzare tutte le componenti di questa infrastruttura.
Partiamo dal tema che, come già detto, ho acquistato su ThemeForest e che di fatto si porta dietro tutta l'applicazione completa sia della grafica che del codice.
Senza entrare troppo nei dettagli si tratta di un classico progetto Nuxt e tra i pacchetti inclusi vi è Nuxt Content (https://content.nuxt.com/) che consente la gestione completa del blog, anche per la parte relativa a tag e categorie.
Più precisamente esiste una cartella chiamata content all'interno della quale sono presenti i file Markdown con estensione .md che corrispondono ai vari articoli.
Il modulo omonimo legge il contenuto di questa cartella e pubblica tutto ciò che c'è al suo interno usando uno schema preimpostato per generare le URL dei singoli articoli ovvero /blog/<nome-file.md>.
In sostanza si sfrutta il nome dato al file per creare il relativo link.
Ma come sono strutturati i file degli articoli?
Partiamo da un esempio pratico.
C'è una parte iniziale che definisce il titolo, la data e l'ultimo aggiornamento effettuato attraverso il campo updated che permette anche di riposizionare l'articolo nella lista dopo aver apportato delle modifiche.
Infatti gli articoli sono elencati in ordine cronologico.
title: "Concetti di Informatica: autenticazione vs autorizzazione"
date: "2024-01-20"
updated: "2024-01-20"
Quindi abbiamo l'autore e il path dell'immagine da visualizzare.
author: "Mauro Cicolella"
img: "/images/blog/copertine/blog-concetti-di-informatica-autenticazione-vs-autorizzazione.png"
Seguono le categorie e i tag (recuperati dalla precedente organizzazione in WordPress) per un'opportuna classificazione.
categories:
- "informatica"
- "concetti-di-informatica"
tags:
- "sicurezza"
Se tutto quello che c'è nella cartella content finisce online, dov'è il vantaggio di utilizzare questa soluzione?
A tale scopo ho creato un'ulteriore cartella denominata content-to-publish all'interno della quale ci sono tutti gli articoli in lavorazione o in bozza, organizzati per argomenti.
In questo modo ho la possibilità comunque di prepararmi un file di base all'interno del quale aggiungere i miei appunti, perché magari mi è venuta un'idea da sviluppare. Spesso aggiungo solo i riferimenti al materiale che mi potrà servire per consultazione.
In sostanza tutto quello che si trova al suo interno non viene pubblicato in automatico ma viene comunque "versionato" tramite GitHub, con tutti i vantaggi del caso.
Quando l'articolo è pronto lo sposto nella cartella content e il gioco è fatto.
Vediamo in che modo.
Il branch principale main contiene l'applicazione Nuxt che può essere eseguita con il classico npm run dev
.
In questo modo le modifiche saranno visibili in tempo reale.
Non appena tutto è pronto per la pubblicazione creo una versione statica del sito, ovvero lancio una build.
Il risultato di questa operazione è ospitato in un branch differente, quello dedicato alle GitHub Pages e che si chiama appunto gh-pages.
Tutte queste operazioni sono completamente automatizzate.
Infatti nel branch principale sono presenti i file che definiscono i workflow delle GitHub Actions: il file build.yml contiene tutti gli step necessari.
Sulla mia macchina ho la copia del repository e vado a lavorare sull'articolo quindi all'interno della cartella content oppure su qualche altro file del sito per aggiornare delle sezioni.
Ovviamente anche le modifiche all'interno della cartella content-to-publish andranno ad innescare la procedura di aggiornamento sebbene i suoi contenuti non saranno pubblicamente visibili prima di essere stati trasferiti in content.
Dunque il branch di riferimento è il main e quando si effettua un push su di esso parte il workflow definito nelle GitHub Actions.
In pratica la build lavora su una versione di Ubuntu installando Node.js versione 14.x (al momento compatibile con l'applicazione) così da ricreare un ambiente all'interno del quale compilare l'applicazione.
runs-on: ubuntu-latest
strategy:
matrix:
node-version: \[14.x\]
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
Quindi si utilizza la Action git-checkout che va a scaricare il codice dal repository online per poi eseguire i comandi richiesti per la generazione della build:
npm ci
(per installare tutte le dipendenze del progetto)
npm run generate
(per creare la versione statica del sito)
- name: git-checkout
uses: actions/checkout@v2
- name: Install all dependencies
run: npm ci
- name: Build
run: npm run generate # The build command of your project
A questo punto occorre effettuare il salvataggio dei file prodotti, operazione che viene eseguita sul branch gh-pages a cui si collega Netlify.
Poichè lavoriamo con un repository privato occorre utilizzare un client SSH attraverso la Action ssh-agent
- name: Install SSH Client 🔑
uses: webfactory/ssh-agent@v0.5.4
with:
ssh-private-key: ${{ secrets.SSH_DEPLOY_KEY }}
Ovviamente è necessaria una coppia di chiavi opportunamente create, di cui quella privata viene inserita all'interno dei Secrets mentre quella pubblica nella configurazione del repository.
Infine utilizziamo github-pages-deploy-action per effettuare il deploy.
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@v4
with:
BASE_BRANCH: main
BRANCH: gh-pages
CLEAN: true
FOLDER: dist
SSH: true
Ma come funziona esattamente?
La Action fa riferimento al branch di base main dove, al termine dell'operazione npm run generate
, la versione statica del sito viene salvata all'interno della cartella dist.
Quindi viene prelevato il contenuto di tale cartella e copiato nella root del branch gh-pages, dopo aver fatto pulizia di tutto.
Per consentire la comunicazione tra i due branch si utilizza proprio SSH con la configurazione vista in precedenza.
La generazione della build sfrutta anche la cache per le dipendenze così da ridurre i tempi di elaborazione, che al momento si attestano intorno ai 2 minuti e mezzo.
L'ultimo step riguarda la pubblicazione vera e propria online sul dominio www.emmecilab.net.
I DNS di questo dominio sono gestiti direttamente da me, opzione scelta in fase di acquisto e registrazione.
Una soluzione del genere offre un'enorme flessibilità nella creazione dei sottodomini.
In particolare ho creato un record CNAME che punta direttamente all'applicazione creata e ospitata da Netlify e che ha una specifica URL.
Sul fronte di Netlify è presente un webhook che monitora il branch gh-pages e ad ogni suo aggiornamento, al termine della build come visto in precedenza, si allinea di conseguenza copiando tutti i file.
Quindi la gestione del sito è molto semplice ed automatizzata: si fanno localmente le modifiche, si carica il codice su GitHub e nel giro di 2-3 minuti il sito è aggiornato.
Teniamo presente che per le build relative a repository privati sono disponibili solo 300 minuti per il piano gratuito di GitHub, tutto sommato sufficienti per i miei scopi.
Inoltre le prestazioni sono più che buone secondo quanto riportato da Page Speed, sebbene siano possibili molte altre ottimizzazioni.
In conclusione la soluzione adottata mi svincola dall'utilizzo di un database, di un server che deve eseguire codice PHP e quindi non devo preoccuparmi di alcun genere di aggiornamento dei sistemi.
Di fatto il sito in sé ha una superficie di attacco praticamente nulla perché costituito da HTML, CSS e un po' di JavaScript.
Naturalmente questa non è l'unica modalità possibile. Si tratta solo di mie scelte personali che ho voluto condividere con tutti.
Mettere in piedi un blog praticamente a costo zero è semplicissimo, con vantaggi non solo economici ma anche in termini di tempo e di impegno necessari per mantenere il tutto in esercizio.
Per ulteriori approfondimenti e per vedere il tutto "dal vivo" vi rimando all'allegato video su YouTube.