Una CDN (Content Delivery Network) è una rete di server distribuiti geograficamente che conserva copie del tuo sito nei data center vicini agli utenti. Il caching è il meccanismo con cui queste copie vengono conservate e aggiornate. Insieme riducono il TTFB da 800ms a meno di 50ms, scaricano il server di origine e migliorano la disponibilità durante i picchi di traffico. Per un sito italiano senza CDN, un utente a Catania che accede a un server ad Amsterdam aggiunge 60-80ms di latenza solo per la distanza fisica.
Come funziona una CDN: dall'origine all'edge
Senza CDN ogni richiesta percorre la distanza tra l'utente e il server di origine. Un utente a Palermo che accede a un sito ospitato ad Amsterdam aggiunge 30-50ms solo di latenza di rete. Con la CDN la risorsa è già nel PoP (Point of Presence) più vicino — forse a Milano o Roma — e viene servita in 5-10ms. Cloudflare ha oltre 300 PoP nel mondo; Vercel Edge Network ne ha più di 100. La differenza percepita dall'utente è netta.
Il funzionamento concreto: alla prima richiesta di una risorsa, il PoP CDN non ha la copia (cache miss) e la recupera dal server di origine. Questa prima richiesta è lenta come senza CDN. Dalla seconda richiesta in poi, il PoP ha la copia in cache (cache hit) e la serve localmente in pochi millisecondi. Il tasso di cache hit (hit ratio) è la metrica chiave: un buon CDN per un sito stattico dovrebbe avere hit ratio > 90%.
Tipi di contenuto: cosa mettere nella CDN
- Asset statici (immagini, CSS, JS, font): candidati perfetti, cambiano raramente, lunga durata in cache (1 anno con fingerprint)
- HTML pre-renderizzato (SSG, ISR): ottimo per contenuti che cambiano ogni ore/giorni con TTL configurabile
- API responses: cacheable con variazioni per autenticazione, parametri di query e header Accept-Language
- Stream video e audio: CDN specializzate (Cloudflare Stream, Bunny.net, Mux) con ottimizzazione per streaming adattivo
- Non cacheable: pagine con contenuto personalizzato per utente loggato, checkout, form POST, dashboard personali
Cache-Control: il linguaggio tra server e browser
L'header HTTP `Cache-Control` istruisce sia i browser che le CDN su come conservare la risposta. `max-age=31536000, immutable` (un anno) è ideale per asset statici con hash nel nome file: il browser non ri-scarica mai finché l'hash non cambia. `no-cache` non significa "non cachare" — significa "rivalidare sempre": il browser usa la copia locale solo se il server conferma che è ancora valida (304 Not Modified). `no-store` è il vero "non cachare mai".
Un errore frequente: impostare `Cache-Control: max-age=3600` su tutti i file senza distinzione. Gli asset con fingerprint (JavaScript, CSS) dovrebbero avere cache di 1 anno: cambiano il nome file ad ogni build quindi la cache vecchia non viene mai usata per contenuto nuovo. Gli asset senza fingerprint (immagini con nome stabile come `logo.webp`) dovrebbero avere cache più breve (ore o giorni) con rivalidazione tramite ETag. L'HTML dovrebbe sempre essere rivalidato: `Cache-Control: no-cache, must-revalidate`.
ETag e Last-Modified: la rivalidazione efficiente
Quando una risorsa scade, il browser non la riscarica necessariamente: invia una richiesta condizionale con `If-None-Match: "etag-value"` o `If-Modified-Since: date`. Se la risorsa non è cambiata il server risponde con 304 Not Modified senza body: vengono trasferiti solo gli header, risparmiando banda. Questo meccanismo è particolarmente efficace per l'HTML che cambia raramente ma non può avere cache lunga per definizione.
L'ETag è calcolato dal server in base al contenuto del file: cambia se e solo se il contenuto cambia. Su Next.js e Vercel le ETag vengono gestite automaticamente. Su WordPress e siti PHP, dipende dalla configurazione del server: Apache genera ETag basate su inode+size+mtime (a volte problematiche in cluster multi-server), nginx usa last-modified di default. Per siti in cluster o con CDN, preferisci ETag basate sul hash del contenuto (configurabile in Apache con `FileETag MTime Size`).
CDN e cache invalidation: il problema più difficile
Si dice che in informatica ci siano solo due cose difficili: nominare le variabili e invalidare le cache. Quando pubblichi un aggiornamento, i file già cachati nella CDN potrebbero rimanere per ore. La soluzione più robusta: usa nomi di file con hash content-based (Webpack e Vite lo fanno automaticamente per JS e CSS) in modo che ogni versione abbia un URL univoco. Alternativa: chiamata di purge alla CDN post-deploy. Nella nostra gestione siti web automatizziamo la purge nel CI/CD.
La strategia di purge automatica che implementiamo: al termine di ogni deploy (GitHub Actions o Vercel Deploy Hooks), inviamo una richiesta di purge alla CDN per le URL HTML (le pagine cambiano ad ogni deploy) mantenendo il cache per gli asset statici che hanno fingerprint. Cloudflare API permette il purge per URL o per tag (cache tag purging, disponibile dal piano Business). Vercel invalida automaticamente il cache dell'Edge Network ad ogni deployment.
Cloudflare: CDN gratuita come punto di partenza
Cloudflare offre CDN gratuita con oltre 300 PoP, protezione DDoS, SSL automatico, e regole di caching configurabili. Per la maggior parte dei siti italiani il piano Free è sufficiente. La configurazione base richiede di puntare i nameserver DNS a Cloudflare: in 5 minuti il sito è protetto e distribuito globalmente. Le Page Rules (piano Pro) e le Cloudflare Rules (disponibili anche in Free) permettono configurazioni avanzate per header, redirect e caching selettivo.
Configurazioni Cloudflare che implementiamo come standard su tutti i siti che gestiamo: Browser Cache TTL impostato a 1 anno per asset statici, Brotli compression abilitata, HTTPS automatico con redirect 301 da HTTP, HTTP/3 con QUIC abilitato, Early Hints per preconnect/preload, e Minification HTML/CSS/JS. Queste impostazioni richiedono 15 minuti di configurazione e migliorano il TTFB medio del 30-50% rispetto al server diretto.
Vercel Edge Network: CDN integrata per Next.js
Vercel integra la CDN direttamente nella piattaforma: le pagine SSG vengono automaticamente distribuite negli edge PoP più vicini all'utente, e le ISR (Incremental Static Regeneration) aggiornano selettivamente solo le pagine modificate senza rebuild completo. Le Edge Functions permettono di eseguire logica server-side dall'edge con latenze sub-millisecondo. Per i nostri progetti Next.js su Vercel il TTFB medio dalle principali città italiane è costantemente sotto i 30ms.
Vercel Edge Network ha data center a Milano e Frankfurt, garantendo latenze eccellenti per gli utenti italiani. I dati che raccogliamo dai progetti Next.js che ospitiamo su Vercel: TTFB medio di 18ms da Milano, 25ms da Roma, 32ms da Napoli per pagine statiche. Per pagine ISR (che richiedono una rigenerazione periodica): TTFB di 18ms dal cache, 250-400ms sulla prima richiesta post-scadenza (poi torna a 18ms per le richieste successive grazie a stale-while-revalidate).
Stale-While-Revalidate: performance e freschezza insieme
La direttiva `stale-while-revalidate` è uno dei trucchi più potenti: dice alla CDN di servire immediatamente la versione cachata (velocità massima), e in background aggiornare la cache con la versione fresca. La prossima richiesta troverà già la versione aggiornata. Next.js ISR usa internamente questo pattern: `revalidate: 60` significa che la pagina viene servita dalla cache per un minuto, poi aggiornata in background senza che nessun utente aspetti la rigenerazione.
Il pattern stale-while-revalidate è ideale per contenuti semi-dinamici: news, prezzi di prodotti, inventario. L'utente vede sempre una risposta immediata (al massimo con 60 secondi di ritardo rispetto all'ultima versione), mentre il server aggiorna in background senza impattare le performance. Per e-commerce italiani con prezzi che cambiano raramente, impostare `revalidate: 300` (5 minuti) su pagine prodotto è spesso il miglior bilanciamento tra freschezza e performance. Se vuoi implementare questa strategia nel tuo sviluppo web, il nostro team può guidarti.




