Skip to content

La compressione HTTP è una delle ottimizzazioni con il miglior rapporto effort/risultato su WordPress: abilitandola si riduce il payload trasferito per HTML, CSS, JavaScript, JSON e SVG del 60-80%, con impatto diretto su TTFB, TTLB e Largest Contentful Paint. La configurazione più efficace oggi combina Brotli (algoritmo di default sui browser moderni) con fallback su GZIP per i client legacy e i middleware che non supportano br.

Questa guida copre la configurazione lato server su Apache (via .htaccess) e Nginx, la verifica corretta dell’header Content-Encoding, la gestione del Vary: Accept-Encoding, i fallback con plugin WordPress e il troubleshooting dei casi più frequenti (Cloudflare, hosting condiviso, cache proxy che invalidano la compressione).

Cos’è la compressione HTTP e perché impatta la SEO

La compressione HTTP è un meccanismo di negoziazione tra client e server: il browser dichiara gli algoritmi supportati tramite l’header Accept-Encoding, il server risponde con la risorsa compressa e un header Content-Encoding che identifica l’algoritmo usato. La specifica di riferimento è RFC 9110 §8.4.

Sul parco dei quattro algoritmi oggi attivi sul web esistono differenze sostanziali in termini di ratio di compressione, velocità di encoding e diffusione:

AlgoritmoContent-EncodingRatio tipico su HTMLSupporto browserUso consigliato
GZIP (DEFLATE + wrapper)gzip70-75%Universale (dal 1999)Fallback obbligatorio
Deflate (raw)deflate70-75%Parziale, implementazioni incoerentiDa evitare
Brotlibr77-82%Tutti i browser moderni su HTTPSPrimario su HTTPS
Zstandardzstd78-83%Chrome 123+, Firefox 126+ (2024)Early adopter

Nota: Brotli via HTTP richiede HTTPS su tutti i browser mainstream. Se il sito è ancora su HTTP, i browser ignorano br e fanno fallback su gzip. Per WordPress la transizione a HTTPS è prerequisito non negoziabile anche per motivi SEO (signal di ranking dal 2014).

L’impatto SEO è misurabile su più dimensioni: riduzione del tempo di trasferimento dei byte dalla rete (che entra direttamente nel TTLB e nella latenza percepita), miglioramento del LCP quando la risorsa dominante è HTML o CSS critico, efficienza del crawl budget (Googlebot scarica più pagine nello stesso window di fetch), riduzione dei costi di banda in uscita. Su un sito WordPress con 5 MB di HTML/CSS/JS non compresso, abilitare Brotli taglia il payload a ~1 MB.

Quanto si risparmia: dati tipici e impatto su TTFB/LCP

Il ratio di compressione dipende dalla tipologia del payload. Testo strutturato e ripetitivo (HTML generato da template, CSS framework, JSON con schema ricorrente) comprime al massimo; binari già compressi (immagini JPG/PNG/WebP/AVIF, font WOFF2, video, ZIP) non hanno guadagno misurabile e il tentativo di ri-compressione introduce solo overhead CPU.

Tipologia risorsaDimensione originaleGZIP (livello 6)Brotli (livello 5)Va compressa?
HTML (homepage WP tipica)180 KB42 KB (-77%)36 KB (-80%)
CSS theme (bundle)250 KB55 KB (-78%)45 KB (-82%)
JavaScript (jQuery + plugin)320 KB95 KB (-70%)82 KB (-74%)
JSON REST API45 KB8 KB (-82%)6 KB (-87%)
SVG icone12 KB3.2 KB (-73%)2.8 KB (-77%)
JPG immagine180 KB179 KB (-0.5%)179 KB (-0.5%)No
WOFF2 font45 KB45 KB (0%)45 KB (0%)No (già Brotli interno)

L’impatto sul TTFB è misurabile solo se il server usa compressione on-the-fly senza cache: in quel caso ogni request paga il costo CPU dell’encoding. Brotli al livello 11 (massimo) su HTML dinamico può aggiungere 30-80ms al TTFB su hosting condiviso: è il motivo per cui in produzione si usano livelli moderati (Brotli 4-6, GZIP 6) o si pre-comprime staticamente con brotli_static / gzip_static su Nginx. Per approfondire le dinamiche di latenza server-side vedi la guida agli HTTP header.

Come verificare se la compressione è attiva

La verifica affidabile si fa da terminale con cURL, forzando l’header Accept-Encoding e ispezionando la risposta. Gli strumenti online sono comodi ma spesso testano solo GZIP e non Brotli, o falliscono con siti dietro CDN.

Verifica via cURL

# Test Brotli
curl -s -I -H "Accept-Encoding: br" https://www.tuosito.it/ | grep -i "content-encoding\|content-length\|vary"

# Test GZIP
curl -s -I -H "Accept-Encoding: gzip" https://www.tuosito.it/ | grep -i "content-encoding\|content-length\|vary"

# Confronto dimensione raw vs compressa
curl -s -o /dev/null -w "Raw: %{size_download} bytes\n" https://www.tuosito.it/wp-content/themes/tema/style.css
curl -s -H "Accept-Encoding: br" -o /dev/null -w "Brotli: %{size_download} bytes\n" https://www.tuosito.it/wp-content/themes/tema/style.css

Nella risposta cerca:

  • content-encoding: br o content-encoding: gzip conferma che la risposta è compressa
  • vary: accept-encoding indica che il server o il proxy differenzia la cache per algoritmo (obbligatorio se c’è caching intermedio)
  • Se content-encoding è assente ma content-length corrisponde al payload raw, la compressione non è attiva per quella risorsa

Verifica dal browser

Chrome DevTools → tab Network → colonna Size: il valore in alto è la dimensione trasferita (compressa), quello in basso il payload effettivo. Se sono uguali, la risorsa non è compressa. Cliccando sulla richiesta, nella sezione Response Headers deve comparire content-encoding.

Abilitare GZIP su Apache via .htaccess

Su Apache la compressione GZIP si attiva tramite il modulo mod_deflate. Il nome del modulo è storico (fa riferimento all’algoritmo DEFLATE interno a GZIP): non esiste un mod_gzip ufficiale su Apache 2.4+. Verifica che il modulo sia caricato prima di procedere:

# Debian/Ubuntu
apache2ctl -M | grep deflate
# Deve restituire: deflate_module (shared)

# CentOS/RHEL
httpd -M | grep deflate

Sul .htaccess nella root di WordPress (o nel VirtualHost), incolla il blocco seguente sopra la sezione # BEGIN WordPress per evitare che WordPress lo sovrascriva durante gli update delle permalink:

<IfModule mod_deflate.c>
  # Compressione per MIME type testuali
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE text/xml
  AddOutputFilterByType DEFLATE text/javascript
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/json
  AddOutputFilterByType DEFLATE application/ld+json
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/atom+xml
  AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
  AddOutputFilterByType DEFLATE font/ttf
  AddOutputFilterByType DEFLATE font/otf
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE image/x-icon

  # Esclude file già compressi
  SetEnvIfNoCase Request_URI \
    \.(?:gif|jpe?g|png|webp|avif|mp4|mp3|ogg|zip|gz|br|woff2?)$ no-gzip

  # Workaround browser legacy (rimovibili se il traffico IE < 6 è zero)
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

  # Vary: Accept-Encoding per proxy e CDN
  <IfModule mod_headers.c>
    Header append Vary Accept-Encoding env=!dont-vary
  </IfModule>
</IfModule>

Il blocco SetEnvIfNoCase è critico: previene che Apache tenti di ricomprimere risorse già compresse (JPG, PNG, WebP, AVIF, WOFF2, archivi), sprecando CPU senza guadagno. L’header Vary: Accept-Encoding è obbligatorio se il sito è dietro un proxy cache (Varnish, Cloudflare, reverse proxy Nginx): senza questo header, la cache potrebbe servire la versione compressa a un client che non la supporta, o viceversa.

Nota: mod_deflate non supporta la regolazione del livello di compressione via direttiva standard. Il default è 6 (bilanciato). Per modificarlo occorre ricompilare o usare DeflateCompressionLevel nella configurazione principale del server, non in .htaccess.

Abilitare Brotli su Apache con mod_brotli

Brotli su Apache richiede mod_brotli, disponibile dalla versione 2.4.26+. Su hosting condivisi il modulo è spesso preinstallato; su VPS va abilitato esplicitamente:

# Debian/Ubuntu
sudo a2enmod brotli
sudo systemctl restart apache2

# Verifica
apache2ctl -M | grep brotli

La configurazione via .htaccess è speculare a quella GZIP ma usa il filtro BROTLI_COMPRESS. Si possono tenere entrambi i filtri attivi: Apache serve Brotli ai client che lo supportano, GZIP agli altri, in base all’Accept-Encoding:

<IfModule mod_brotli.c>
  AddOutputFilterByType BROTLI_COMPRESS text/html
  AddOutputFilterByType BROTLI_COMPRESS text/plain
  AddOutputFilterByType BROTLI_COMPRESS text/css
  AddOutputFilterByType BROTLI_COMPRESS text/xml
  AddOutputFilterByType BROTLI_COMPRESS text/javascript
  AddOutputFilterByType BROTLI_COMPRESS application/javascript
  AddOutputFilterByType BROTLI_COMPRESS application/json
  AddOutputFilterByType BROTLI_COMPRESS application/ld+json
  AddOutputFilterByType BROTLI_COMPRESS application/xml
  AddOutputFilterByType BROTLI_COMPRESS application/xhtml+xml
  AddOutputFilterByType BROTLI_COMPRESS application/rss+xml
  AddOutputFilterByType BROTLI_COMPRESS application/atom+xml
  AddOutputFilterByType BROTLI_COMPRESS image/svg+xml

  # Livello compressione (0-11, default 11). 5 bilancia CPU/ratio.
  BrotliCompressionQuality 5

  # Window size (10-24, default 22). 18 è il sweet spot per HTML dinamico.
  BrotliCompressionWindow 18
</IfModule>

Il livello 11 di Brotli comprime al massimo ma è ~10x più lento del livello 5 in encoding. Per HTML generato dinamicamente da WordPress su hosting condiviso, il livello 4-5 è la scelta corretta: differenza di ratio trascurabile (1-2 punti percentuali), costo CPU accettabile. Il livello 11 va usato solo su risorse statiche pre-compresse a deploy-time (opzione non supportata nativamente da Apache senza script custom).

Metodo alternativo: mod_filter per compressione granulare

Quando AddOutputFilterByType non funziona (configurazioni custom, conflitti con altri moduli, regole di rewrite che alterano il MIME), si ricorre a mod_filter con FilterProvider basato su regex. Il vantaggio è il controllo granulare: si può filtrare per header, URI, variabili d’ambiente.

<IfModule mod_filter.c>
  FilterDeclare COMPRESS
  FilterProvider COMPRESS DEFLATE \
    "%{Content_Type} =~ m#^text/(html|css|plain|xml|javascript)#"
  FilterProvider COMPRESS DEFLATE \
    "%{Content_Type} =~ m#^application/(javascript|json|xml|ld\+json|rss\+xml|atom\+xml|xhtml\+xml)#"
  FilterProvider COMPRESS DEFLATE \
    "%{Content_Type} =~ m#^image/svg\+xml#"
  FilterChain COMPRESS
  FilterProtocol COMPRESS DEFLATE change=yes;byteranges=no
</IfModule>

La direttiva FilterProtocol DEFLATE change=yes;byteranges=no dichiara che la risposta cambia (il Content-Length va ricalcolato) e che i byte range non sono supportati sul contenuto compresso — comportamento atteso, dato che una richiesta parziale su un flusso DEFLATE non è decodificabile.

Abilitare GZIP e Brotli su Nginx

Nginx non legge .htaccess: la configurazione della compressione va inserita in /etc/nginx/nginx.conf (blocco http, applicata globalmente) oppure nel server block del sito in /etc/nginx/sites-available/<sito>. Per i dettagli sul tuning di Nginx per WordPress fai riferimento alla guida dedicata alla configurazione Nginx.

Blocco GZIP

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 256;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_disable "MSIE [1-6]\.";
gzip_types
  application/atom+xml
  application/javascript
  application/json
  application/ld+json
  application/manifest+json
  application/rss+xml
  application/vnd.ms-fontobject
  application/x-font-ttf
  application/x-web-app-manifest+json
  application/xhtml+xml
  application/xml
  font/opentype
  image/svg+xml
  image/x-icon
  text/css
  text/javascript
  text/plain
  text/xml;

Parametri chiave:

  • gzip_comp_level 6: sopra il 6 il ratio migliora poco (<2%) ma la CPU cresce rapidamente
  • gzip_min_length 256: sotto i 256 byte la compressione aggiunge overhead più grande del risparmio
  • gzip_proxied any: comprime anche le risposte passate via reverse proxy (necessario se Nginx è davanti ad Apache o PHP-FPM)
  • gzip_vary on: aggiunge automaticamente Vary: Accept-Encoding alle risposte

Blocco Brotli

Brotli su Nginx richiede il modulo ngx_brotli, non incluso di default: va compilato da sorgente o installato da repository dedicati (es. Cloudflare su Ubuntu, oppure il pacchetto libnginx-mod-http-brotli su alcune distribuzioni). Verifica il supporto con nginx -V 2>&1 | grep brotli.

brotli on;
brotli_comp_level 5;
brotli_static on;
brotli_min_length 256;
brotli_types
  application/atom+xml
  application/javascript
  application/json
  application/ld+json
  application/rss+xml
  application/vnd.ms-fontobject
  application/xhtml+xml
  application/xml
  font/opentype
  image/svg+xml
  text/css
  text/javascript
  text/plain
  text/xml;

La direttiva brotli_static on è uno dei vantaggi operativi più significativi: se a fianco del file style.css esiste style.css.br, Nginx lo serve direttamente senza compressione runtime. In una pipeline di deploy (Gulp, Webpack, CI/CD) si pre-comprimono gli asset statici al livello 11, ottenendo ratio massimo con zero costo CPU a request time.

Dopo ogni modifica, ricarica la configurazione senza dropare le connessioni attive:

nginx -t && systemctl reload nginx

Plugin WordPress per chi non può toccare il server

Su hosting managed o condivisi senza accesso a .htaccess o a nginx.conf, la compressione si attiva tramite plugin. Tutti quelli citati operano scrivendo regole nel .htaccess o generando file statici pre-compressi nella cartella cache:

  • WP Rocket: abilita GZIP via .htaccess automaticamente. Non genera Brotli ma è compatibile con Brotli lato server se attivo. L’opzione “Abilita compressione GZIP” è in Impostazioni > Cache
  • W3 Total Cache: sezione Browser Cache > HTTP (gzip) compression. Genera anche il blocco mod_deflate nel .htaccess
  • LiteSpeed Cache: su server LiteSpeed/OpenLiteSpeed include supporto nativo a GZIP e Brotli, gestiti dal server senza intervento PHP
  • Cache Enabler + Autoptimize: Cache Enabler genera varianti pre-compresse (.gz) se l’opzione “Create an additional cached version for compression” è attiva

Attenzione: plugin e configurazione server non vanno sommati. Se il webserver comprime già la risposta, un plugin che tenta di applicare ob_gzhandler a livello PHP produce una doppia compressione che i browser non riescono a decodificare (errore ERR_CONTENT_DECODING_FAILED). Usa uno solo dei due strati.

Troubleshooting: compressione che non funziona

La risposta non ha il Content-Encoding

  • Il modulo non è caricato: verifica con apache2ctl -M o nginx -V
  • Il MIME type non è nella lista: controlla Content-Type della risposta e aggiungilo ai filtri
  • Il file è sotto la soglia gzip_min_length / brotli_min_length: risposte < 256 byte non vengono compresse
  • Un reverse proxy o CDN sta decomprimendo la risposta: controlla l’header Via e i log del proxy

Cloudflare serve HTML non compresso

Cloudflare comprime di default in GZIP e Brotli solo se il client lo richiede via Accept-Encoding e la feature Brotli è attiva (Speed > Optimization > Brotli). Casi tipici di fallimento:

  • Cache-Control: private o no-store bypassa la cache Cloudflare e disabilita anche la compressione edge in alcuni piani
  • Risorse con query string non vengono cachate (e quindi non compresse edge) senza Page Rule esplicita
  • Development Mode attivo bypassa tutto il layer edge

Doppia compressione

Se PHP usa zlib.output_compression = On (in php.ini) e il webserver a monte applica mod_deflate, il browser riceve un payload compresso due volte. Disattiva una delle due. La via pulita è lasciare la compressione al webserver e impostare zlib.output_compression = Off nel php.ini.

Vary: Accept-Encoding mancante

Senza Vary: Accept-Encoding, un proxy cache può memorizzare la versione compressa e servirla a un client che ha inviato Accept-Encoding: identity, con risultato illeggibile. Googlebot in alcuni casi richiede risposte non compresse per il parsing: il Vary garantisce che la cache risponda correttamente. Per i dettagli sui protocolli di trasporto e caching vedi la guida ai protocolli HTTP.

FAQ su GZIP e Brotli

Meglio GZIP o Brotli?

Entrambi, con Brotli primario e GZIP come fallback. Brotli ha ratio superiore del 5-10% su HTML/CSS/JS ma non è supportato dai browser legacy o da alcuni middleware. Il server negozia automaticamente in base all’Accept-Encoding inviato dal client.

Quale livello di compressione usare?

Per HTML dinamico: GZIP 6, Brotli 4-5. Sopra questi valori il ratio migliora marginalmente ma il costo CPU cresce rapidamente. Per asset statici pre-compressi a deploy time: massimo consentito (GZIP 9, Brotli 11), zero impatto runtime.

HTTP/2 e HTTP/3 rendono la compressione meno utile?

No. HTTP/2 comprime gli header (HPACK) e HTTP/3 usa QPACK, ma il body resta soggetto alla compressione negoziata via Content-Encoding. Il guadagno di Brotli su 200 KB di HTML è indipendente dal protocollo di trasporto.

Le immagini vanno compresse con GZIP?

No. JPG, PNG, WebP, AVIF, GIF sono già formati compressi. Applicare GZIP o Brotli aggiunge overhead CPU per un guadagno < 1%. L’ottimizzazione delle immagini si fa scegliendo il formato corretto (AVIF/WebP per foto, SVG per icone) e dimensionando correttamente le risoluzioni. Per l’ottimizzazione generale del front-end vedi la guida all’ottimizzazione CSS.

I file WOFF2 beneficiano di GZIP?

No. Il formato WOFF2 include già compressione Brotli interna. Escluderli dalla compressione tramite SetEnvIfNoCase Request_URI \.(woff2)$ no-gzip. WOFF legacy (senza “2”) invece usa zlib e guadagna marginalmente dalla compressione, ma è praticamente deprecato.

Come misurare l’impatto reale sul mio sito?

Confronta il transferSize vs encodedBodySize in Navigation Timing API, oppure usa PageSpeed Insights / WebPageTest in modalità “repeat view” con e senza compressione abilitata. Il Lighthouse audit “Enable text compression” segnala esplicitamente le risorse non compresse. Per un piano di ottimizzazione server completo consulta la guida all’ottimizzazione del web server.

Articoli correlati

21 min lettura

Ridurre i tempi di risposta del server è vitale per abbattere il TTFB e dominare metriche come LCP e INP. Workflow tecnico per aumentare la velocità dell'hosting: dalla transizione verso VPS alla configurazione avanzata dello stack LEMP per ottenere server realmente accelerati.
33 mi piace
7 min lettura

Forza il download anticipato degli asset critici tramite link rel="preload" per ottimizzare la critical request chain. Analisi sull'implementazione del css preload e dei font, con focus tecnico sulle differenze architetturali e di priorità esecutiva rispetto alle direttive prefetch.
25 mi piace

Autore

Commenti |2

Lascia un commento Lascia un commento
  1. G Marchesi 1 commento

    Grazie mitico :9 rapido ed indolore!

    1. Giovanni Sacheli 774 risposte

      Grazie del commento Marchesi, a presto!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Ultimi articoli aggiornati

22 min lettura

Difendere WordPress dai commenti spam con una strategia defense in depth a tre layer: configurazioni applicative, regole edge su Cloudflare, barriere a livello web server. Honeypot PHP, regole .htaccess e Nginx modernizzate, Cloudflare Turnstile, fail2ban. Snippet completi pronti da incollare.
0 mi piace
22 min lettura

Analisi tecnica della persistenza dei dati nel protocollo HTTP tramite header Set-Cookie. Comprendere la meccanica dei cookie, attributi come Max-Age e i limiti di Googlebot come crawler stateless è essenziale per diagnosticare problemi di rendering e involuntary cloaking.
3 mi piace
19 min lettura

Analisi dell'architettura RAG nativa per WordPress sviluppata interamente in PHP e MySQL, senza dipendenze da database vettoriali esterni. Il sistema supera i limiti della ricerca lessicale integrando la ricerca semantica su VPS o hosting condivisi con meno di 1GB di RAM.
2 mi piace
7 min lettura

La gestione dei 404 durante le migrazioni richiede automazione per preservare la link equity. migTool è uno script Python progettato per automatizzare la mappatura dei redirect 301 intelligenti, ottimizzando il processo di reindirizzamento ed eliminando le inefficienze manuali.
5 mi piace

Richiedi un preventivo SEO e Google Ads

Porta il tuo sito web al livello successivo con l’esperienza di EVE Milano. La nostra agenzia di Search Marketing ha ricevuto oltre 1207 richieste di preventivo, un segnale chiaro della fiducia che imprenditori e manager, come te, ripongono nella nostra specializzazione tecnica e verticale nella SEO e PPC. Se la tua organizzazione cerca competenze specifiche per emergere nei risultati di Google, noi siamo pronti a fornire quel valore aggiunto. Richiedi un preventivo ora e scopri la differenza tra noi e gli altri.
Richiedi un preventivo

Vuoi ricevere un avviso al mese con le nuove guide pubblicate?

Iscriviti alla newsletter!