Come funziona FolioPress: una pagina, tutte le lingue
La maggior parte dei siti web parla una sola lingua. Nel momento in cui un'attività ne ha bisogno di una seconda, le cose si complicano: un plugin di traduzione appiccicato sopra, una seconda copia del sito da tenere sincronizzata, oppure un piano più costoso solo per scrivere «Hello» accanto a «Ciao».
FolioPress è nato dall'idea opposta: una pagina non è una pagina con delle traduzioni attaccate, ma è tutte le sue lingue insieme. Il titolo, l'indirizzo, il menu, i tag, ciò che vede Google: tutto esiste in ogni lingua che scegli, fin dal primo minuto.
Tutto è iniziato dal desiderio di sostituire un CMS fatto su misura a cui erano state aggiunte più lingue a forza. Cercando alternative, ho scoperto che fallivano tutte miseramente nell'integrare contenuti multilingue in un costruttore di siti semplice da usare.
Questo è uno sguardo dietro le quinte: come si incastra il tutto, i compromessi dietro le scelte e le cose che si sono rotte lungo la strada.
Vista dall'alto
Una visita viaggia da sinistra a destra. La torre di controllo non si trova mai su quel percorso. Si limita a costruire, traslocare e accudire i siti.
Una visita a un sito FolioPress fa tre tappe. Cloudflare la intercetta vicino al visitatore e filtra la spazzatura. Una porta d'ingresso (Traefik, che si occupa anche dei certificati HTTPS) guarda l'indirizzo e trova il sito giusto. A rispondere è il sito stesso, da un condominio, dove molti piccoli siti vivono fianco a fianco, oppure da una casa tutta sua quando ha molto traffico. In disparte, una torre di controllo gestisce tutto ciò che un visitatore non vede mai: iscrizioni, fatturazione, indirizzi web, aggiornamenti e controlli di salute, con un piccolo custode su ogni server che avvia e ferma i siti.
È tutto Python, in tre livelli scritti da me: un framework web (pystarter, basato su FastAPI), il sistema di gestione dei contenuti sopra di esso (foliopress) e la torre di controllo (Forestry). I pagamenti passano da Polar, che fa da venditore ufficiale (il cosiddetto merchant of record), quindi l'IVA europea è un grattacapo loro e non mio.
Ogni pagina, ogni lingua
Ogni lingua ha il suo indirizzo leggibile e, se vuoi, il suo dominio.
Quando una guesthouse di Lisbona scrive la sua pagina «Chi siamo», la scrive una volta per lingua, e ogni versione riceve un indirizzo che suona naturale in quella lingua. Sotto il cofano, una traduzione è un record accanto all'originale, non una copia della pagina: titoli, indirizzi, menu, tag e descrizioni per i motori di ricerca esistono tutti per lingua. I visitatori arrivano automaticamente nella loro lingua, e Google sa esattamente quale pagina è quale (grazie ai tag hreflang e a una sitemap per lingua), così la versione portoghese compare nelle ricerche in portoghese. Vuoi il sito tedesco su un suo dominio .de? Si può fare anche questo. E quando preferisci non partire da una pagina bianca, una prima bozza di ogni traduzione fatta con l'IA è a un clic di distanza: tu la rivedi, tu decidi.
Ogni sito conserva tutto questo nel proprio piccolo file di database (SQLite). Non c'è nessun server di database da gestire, il backup notturno esterno è una semplice copia di file, e un intero sito è una cartella che si può spostare, ripristinare o eliminare in un colpo solo.
I siti piccoli condividono, quelli trafficati traslocano
La maggior parte dei siti web è tranquilla quasi sempre. Dare a ciascuno i propri macchinari sarebbe come affittare un'intera casa a qualcuno che passa due volte l'anno. Così i siti piccoli condividono un condominio (un solo processo, dati rigorosamente separati) e la piattaforma tiene d'occhio il traffico di ogni sito. Quando uno si anima, trasloca in una casa tutta sua. Quando si calma per un paio di settimane, torna indietro.
Condividere un condominio funziona solo se i muri sono solidi. Quando arriva una richiesta, il processo condiviso guarda l'indirizzo e poi passa al database e alle impostazioni di quel sito solo per quella richiesta (usando i contextvars di Python), così un sito non vede mai i dati di un altro. Il container di ogni sito ha anche una propria rete privata con un firewall in uscita. E visto che i proprietari possono caricare e modificare i propri temi, quei template girano in una sandbox con limiti di tempo, di output e di memoria.
Capire cosa conta come «trafficato» ha richiesto qualche tentativo. Una singola newsletter, o un crawler in preda a una raffica improvvisa, non dovrebbe far sembrare popolare un sito. Così il punteggio è la giornata tipica del sito nell'ultima settimana (la mediana), più quanto sono intense le sue ore di punta (l'ora al 95° percentile), il che esclude la manciata di ore più scatenate.
Giorno di trasloco, senza chiudere bottega
Ogni aggiornamento, e ogni trasloco tra il condominio e una casa tutta sua, avviene mentre il sito continua a servire i visitatori. Gli ingegneri lo chiamano deploy blue/green: una nuova copia del sito si avvia accanto a quella vecchia, e solo quando è in salute la porta d'ingresso inizia a mandarle gente. Due dettagli lo rendono davvero impercettibile. Il custode non dà per scontato che la porta d'ingresso abbia fatto il cambio: controlla i numeri della porta d'ingresso stessa finché non è avvenuto. E alla vecchia copia viene chiesto prima di «svuotarsi»: smette di accettare nuovi visitatori, finisce quello che stava facendo e solo allora si spegne.
Cose che si sono rotte
Niente ti insegna com'è fatto un sistema quanto guardarlo andare in pezzi. Alcune delle mie preferite:
La volta in cui ho buttato giù tutto da solo. Per evitare che una pagina lenta rallentasse tutte le altre, ho spostato il rendering delle pagine su un pool di thread di lavoro. Poi, per verificare che i traslochi dei siti filassero lisci, ho scaricato un'ondata di traffico di prova sui siti in produzione. Si sono bloccati per nove minuti e sono rimasti bloccati anche dopo che il traffico si era fermato. Ogni pagina teneva occupata una connessione al database mentre ne chiedeva una seconda e, con decine di thread e un pool di quindici connessioni, ogni thread ha finito per aspettarne un altro. Nel frattempo il controllo di salute, che non toccava mai il database, riferiva allegramente che andava tutto bene.
La soluzione: pool di database che non possono andare in deadlock, un limitatore che trasforma un sovraccarico in un rapido «riprova» invece che in un blocco (con una quota equa per ogni sito, così un sito trafficato non può affamare gli altri), un controllo di salute che si accorge di un processo bloccato, un watchdog che lo riavvia e una regola ferma su dove si fanno i test di carico.
Il singhiozzo di 45 secondi. La maggior parte dei traslochi filava liscia, ma un tipo no: se il trasloco cambiava le regole di instradamento del sito, la copia vecchia e quella nuova descrivevano per un attimo la stessa rotta in due modi diversi. La porta d'ingresso, incapace di decidere a quale credere, non ne serviva nessuna per circa 45 secondi. Tutto il resto del trasloco era corretto, ed è proprio per questo che ci è voluto un po' per accorgersene.
Un sito minuscolo al 100% di CPU. Un piccolo negozio con qualche centinaio di visitatori al giorno continuava a mandare il processore al massimo. I colpevoli non erano i clienti, ma scanner automatici che sparavano più di cento richieste in dieci secondi, a caccia di file come /.env o /wp-login.php che un sito FolioPress non ha mai. Ognuna riceveva una bella pagina «non trovata», curata in ogni dettaglio: circa 70 ms di lavoro, moltiplicati per cento.
La soluzione: ora quelle richieste ricevono un «Not found» di nove byte prima che parta qualsiasi lavoro vero, e Cloudflare respinge la maggior parte di esse prima ancora che arrivino.
«Server non trovato» per un sito che era online. L'indirizzo web di un sito nuovo di zecca viene creato durante la configurazione. Se qualcosa cercava il nome un attimo troppo presto, i provider internet si ricordavano che «questo nome non esiste» per un massimo di trenta minuti, anche se il sito funzionava benissimo. La soluzione è stata un indirizzo jolly (wildcard), così ogni nome sotto foliopress.io esiste sempre; i nomi senza un sito ricevono una pagina cordiale che dice «qui non c'è nessun sito».
I vicini. Ospitare tanti siti fianco a fianco solleva domande che un sito singolo non deve mai porsi: cosa può fare il codice di un sito a un altro, e cosa può rivendicare un sito che non è suo. Una revisione di sicurezza prima di aprire le iscrizioni ha fatto emergere alcuni di questi problemi. Sono stati tutti risolti: cookie più restrittivi, prova di proprietà per i domini personalizzati e ogni sito montato nella propria cartella separata, così nessun sito può raggiungere i file di un altro.
Cosa direi a chi sta iniziando
- I pezzi noiosi e collaudati portano lontano. SQLite, un solo framework, container semplici. La maggior parte dei problemi difficili stava nelle giunture tra l'uno e l'altro.
- Misura prima di crederci. Il punteggio del traffico, il disservizio e i picchi di CPU all'inizio sembravano tutti qualcos'altro.
- Progetta per la maggioranza silenziosa. La maggior parte dei siti è piccola. Rendere economico il piccolo è ciò che rende possibile tutto il resto.
Cosa c'è dopo
Pubblicazione sui social, diagrammi mermaid, ma soprattutto aspettare il feedback degli utenti per dare forma al futuro.
Se hai un sito che deve parlare più di una lingua, prova FolioPress su foliopress.io: i primi 30 giorni sono gratuiti. E se sei un tipo tecnico, mi piacerebbe sapere come l'avresti costruito tu.