Skip to content

Guida completa ai comandi CLI per l’analisi, l’ottimizzazione e il monitoraggio SEO

In questi anni di vibe-coding va molto di moda usare il terminale, allora ho pensato: perché non fare una guida SEO da terminale?

I tool SEO con interfaccia grafica astraggono complessità, ma a un costo che raramente viene dichiarato: opacità sui dati grezzi, zero riproducibilità delle analisi, lock-in funzionale verso un singolo vendor. Il terminale opera al livello opposto. Ogni operazione è trasparente, scriptabile, verificabile. Non c’è magia dietro un output: c’è un comando documentato che produce un risultato deterministico. Per chi conduce audit tecnici su siti con architetture complesse — rendering ibrido, migliaia di template, infrastrutture multi-CDN — il terminale non è un’alternativa ai tool GUI. È il livello sottostante su cui quei tool sono costruiti.

Googlebot è un client HTTP. curl replica esattamente la sua logica di fetch dell’HTML iniziale — stessi header, stesso protocollo, stessa negoziazione TLS. Le pipeline composabili (curl | grep | awk | jq) permettono di costruire analisi custom impossibili con qualsiasi tool preconfezionato, perché non sei vincolato a ciò che qualcun altro ha deciso di mostrarti. E soprattutto: uno script bash è un audit documentato. È replicabile su qualsiasi macchina, versionabile con git, condivisibile con il team senza licenze o abbonamenti. Quando un cliente chiede “come hai ottenuto quel dato?”, la risposta è il comando stesso.

Questa guida raccoglie comandi e workflow consolidati in anni di audit tecnici su siti con architetture eterogenee — da e-commerce con milioni di URL e filtri faceted navigation a portali editoriali con rendering ibrido SSR/CSR, passando per piattaforme SaaS multi-tenant con decine di sottodomini. Ogni comando è stato testato in contesti di produzione reali, non in ambienti di laboratorio. Le soglie, le interpretazioni e i casi d’uso riportati derivano da problemi concreti risolti sul campo.

L’articolo è organizzato per fasi di un audit tecnico: si parte dall’analisi di rete e prestazioni, si passa a DNS, contenuti, crawling, header HTTP, sicurezza, log server, fino ad automazione, reporting e strumenti avanzati. Ogni sezione è indipendente — il lettore può consultare solo ciò che gli serve senza leggere l’intero documento. L’indice che segue permette di navigare direttamente alla sezione di interesse.

La guida si rivolge a professionisti SEO con esperienza su audit tecnici, sviluppatori full-stack che gestiscono aspetti SEO dell’infrastruttura e data analyst che lavorano con dati di crawling e log. Tutti i comandi sono testati su Linux e macOS (per Windows si usa WSL). Si assume familiarità con il terminale, il protocollo HTTP e i concetti SEO fondamentali: crawling, indexing, rendering, canonicalization.

Ogni affermazione tecnica presente in questa guida è supportata da fonti primarie: documentazione ufficiale Google Search Central, RFC IETF, dichiarazioni pubbliche di ingegneri Google (Gary Illyes, John Mueller, Martin Splitt), report di settore verificabili. Le soglie di riferimento per metriche come TTFB, LCP e dimensioni delle risorse sono aggiornate a febbraio 2026.


Come usare questa guida

Questa sezione spiega come eseguire i comandi e gli script presenti nel documento. Se hai già familiarità con il terminale, puoi saltarla.

Sistema operativo e ambiente

Tutti i comandi di questa guida sono scritti per terminali Unix/Linux e funzionano su:

  • Linux (Ubuntu, Debian, CentOS, Arch, ecc.) — ambiente nativo, tutto funziona direttamente.
  • macOS — funziona quasi tutto. Alcune utility GNU (come grep -P per le regex Perl) richiedono l’installazione della versione GNU tramite Homebrew: brew install grep coreutils gnu-sed.
  • Windows — non funziona nativamente nel Prompt dei comandi o PowerShell. Hai tre opzioni:
    • WSL (Windows Subsystem for Linux) — la scelta consigliata. Installa WSL2 con Ubuntu dal Microsoft Store, poi apri il terminale Ubuntu e sei in un ambiente Linux completo.Git Bash — funziona per i comandi semplici (curl, grep), ma ha limitazioni su script complessi.Docker — avvia un container Linux (docker run -it ubuntu bash) per un ambiente isolato e riproducibile.

Per aprire il terminale: su macOS cerca “Terminal” in Spotlight; su Linux usa Ctrl+Alt+T; su Windows con WSL cerca “Ubuntu” nel menu Start.

Tre tipi di codice in questa guida

Nel documento trovi tre tipi di blocchi di codice con utilizzi diversi.

Tipo 1 — Comando singolo (copia-incolla diretto)

La maggior parte dei comandi nella guida sono singole righe eseguibili direttamente. Copia la riga, incollala nel terminale, premi Invio.

curl -sI https://example.com | grep -i "content-encoding"

Funzionamento: copi quella riga esatta, la incolli nel terminale, sostituisci example.com con il dominio che vuoi analizzare, premi Invio. Il risultato appare immediatamente a schermo.

Tipo 2 — Blocco multi-riga (copia-incolla dell’intero blocco)

Alcuni comandi si estendono su più righe, collegati dal carattere \ a fine riga (che dice al terminale “il comando continua nella riga successiva”) oppure racchiusi in un ciclo for/while.

curl -o /dev/null -s -w "\
    DNS Lookup:        %{time_namelookup}s\n\
    TCP Connect:       %{time_connect}s\n\
    Time to First Byte:%{time_starttransfer}s\n" \
    https://example.com

Funzionamento: seleziona e copia tutto il blocco (da curl fino a example.com), incollalo nel terminale in un’unica operazione, premi Invio. Il terminale riconosce i \ e tratta il tutto come un singolo comando.

Tipo 3 — Script bash (salvare come file, poi eseguire)

Gli script più lunghi iniziano con #!/bin/bash e sono pensati per essere salvati come file .sh, resi eseguibili e lanciati. Non vanno incollati riga per riga nel terminale.

Procedura:

# 1. Crea il file con un editor di testo (nano è il più semplice)
nano seo-audit.sh

# 2. Incolla l'intero contenuto dello script nell'editor
#    (su nano: Ctrl+Shift+V per incollare, Ctrl+O per salvare, Ctrl+X per uscire)

# 3. Rendi il file eseguibile
chmod +x seo-audit.sh

# 4. Esegui lo script
./seo-audit.sh example.com

In alternativa, puoi creare il file in un solo passaggio senza aprire un editor:

cat > seo-audit.sh << 'FINE'
#!/bin/bash
# Qui va incollato l'intero contenuto dello script
FINE

chmod +x seo-audit.sh
./seo-audit.sh example.com

Sostituire i placeholder

In tutti i comandi della guida, i valori da personalizzare sono:

PlaceholderCosa inserire
example.comIl dominio del sito da analizzare
https://example.comL’URL completo della pagina target
urls.txtUn file di testo con un URL per riga, da creare tu
API_KEYLa tua chiave API (es. Google PageSpeed Insights)
/var/log/nginx/access.logIl percorso reale dei log del tuo server

Per creare un file urls.txt:

# Manualmente
nano urls.txt
# Scrivi un URL per riga, salva con Ctrl+O, esci con Ctrl+X

# Oppure in un solo comando
cat > urls.txt << 'FINE'
https://miosito.it/
https://miosito.it/chi-siamo
https://miosito.it/servizi
https://miosito.it/blog
FINE

Dipendenze e strumenti necessari

La maggior parte dei comandi usa utility preinstallate su Linux/macOS (curl, grep, awk, sed, dig, openssl). Alcuni strumenti richiedono un’installazione separata:

# Verificare se un comando è disponibile
which curl      # Se non restituisce nulla, il comando non è installato
curl --version  # Verificare versione e supporto (es. SSL, HTTP/2)

# Installare i tool mancanti (Ubuntu/Debian)
sudo apt update && sudo apt install -y curl wget jq nmap mtr whois dnsutils

# macOS con Homebrew
brew install curl wget jq nmap mtr whois pup

Per gli strumenti avanzati citati nella guida (Sezione 3 e 10):

# pup — parser HTML con selettori CSS (consigliato)
go install github.com/ericchiang/pup@latest    # richiede Go
# oppure su macOS:
brew install pup

# Lighthouse — audit Core Web Vitals
npm install -g lighthouse    # richiede Node.js

# httpie — alternativa leggibile a curl
pip install httpie           # richiede Python

Per una reference più ampia dei comandi Linux utilizzabili in ambito server e web, consultare la lista dei comandi Ubuntu per la gestione di un web server.

Dove finiscono i risultati

I comandi di questa guida producono output in tre modi diversi:

  • A schermo — la maggior parte dei comandi stampa il risultato direttamente nel terminale. Lo vedi e basta.
  • In un file — i comandi con > (sovrascrive) o >> (accoda) salvano l’output in un file. Esempio: > report.txt crea il file report.txt nella cartella corrente.
  • Tramite pipe | — il simbolo | passa l’output di un comando come input al successivo. Esempio: curl -s https://example.com | grep "title" scarica la pagina e poi cerca “title” nel contenuto.

Per sapere in quale cartella ti trovi e dove verranno creati i file:

pwd              # Mostra la cartella corrente
ls -la           # Elenca i file nella cartella corrente
cat report.txt   # Visualizza il contenuto di un file

1. Analisi di Rete e Prestazioni

L’analisi di rete è il punto di partenza di qualsiasi audit tecnico. Prima di valutare contenuti, struttura o indicizzazione, è necessario verificare che il sito sia raggiungibile, che i tempi di risposta rientrino nelle soglie accettabili e che l’infrastruttura regga il carico previsto. I dati raccolti in questa fase — TTFB, latenza, catene di redirect, comportamento sotto stress — costituiscono il baseline quantitativo su cui costruire tutte le analisi successive.

1.1 curl — Il coltellino svizzero dell’HTTP

curl è lo strumento fondamentale per qualsiasi analisi SEO da terminale. Permette di simulare richieste HTTP, misurare tempi di risposta, seguire redirect e ispezionare header.

Limite importante: curl recupera solo l’HTML iniziale (Initial HTML) restituito dal server. Su siti che utilizzano framework JavaScript (React, Vue, Angular, Next.js in modalità CSR) il contenuto visibile dall’utente (e da Googlebot) viene generato lato client dopo l’esecuzione di JS. Per l’analisi del DOM renderizzato, vedi la Sezione 3.0 — Initial HTML vs Rendered DOM.

Misurare il TTFB (Time to First Byte)

Il TTFB è una metrica diagnostica fondamentale che precede tutti i Core Web Vitals legati al caricamento. Un TTFB elevato impatta direttamente il Largest Contentful Paint (LCP). Questo comando misura ogni fase della connessione.

curl -o /dev/null -s -w "\
    DNS Lookup:        %{time_namelookup}s\n\
    TCP Connect:       %{time_connect}s\n\
    TLS Handshake:     %{time_appconnect}s\n\
    Time to First Byte:%{time_starttransfer}s\n\
    Total Time:        %{time_total}s\n\
    Download Speed:    %{speed_download} bytes/sec\n\
    HTTP Code:         %{http_code}\n\
    Size Download:     %{size_download} bytes\n\
    Redirect URL:      %{redirect_url}\n" \
    https://example.com

Output spiegato:

  • time_namelookup — Tempo di risoluzione DNS. Valori >100ms indicano DNS lento (considera Cloudflare DNS o Route53).
  • time_connect — Tempo per stabilire la connessione TCP. Dipende dalla distanza geografica dal server.
  • time_appconnect — Tempo per completare l’handshake TLS. Valori alti suggeriscono certificati pesanti o mancanza di TLS session resumption.
  • time_starttransferQuesto è il TTFB. Le soglie ufficiali Google (web.dev/articles/ttfb, aggiornato novembre 2025) sono: ≤ 800ms buono, 800ms–1.8s da migliorare, > 1.8s critico. Attenzione: il TTFB non è un Core Web Vital. Google lo classifica come metrica diagnostica. La stessa documentazione precisa: “it’s not absolutely necessary that sites meet the ‘good’ TTFB threshold, provided that it doesn’t impede their ability to score well on the metrics that matter”. Detto questo, un TTFB elevato impatta direttamente il Largest Contentful Paint, quindi va ottimizzato.
  • time_total — Tempo totale di download. Impatta l’esperienza utente e indirettamente il crawl budget.

Nota pratica: Il TTFB misurato da curl (lab data, singola richiesta, rete locale) non include redirect e può differire significativamente dal TTFB misurato in campo (CrUX, 75° percentile su 28 giorni di dati reali). Per un confronto completo, affiancare sempre il dato di PageSpeed Insights. In un caso reale, l’analisi TTFB via curl ci ha permesso di isolare un ritardo di 800ms causato unicamente dall’handshake TLS mal configurato su un cluster Nginx — problema invisibile nei dati CrUX aggregati.

Salvare i tempi in formato CSV per analisi comparative

for url in $(cat urls.txt); do
  curl -o /dev/null -s -w "$url,%{time_namelookup},%{time_connect},%{time_starttransfer},%{time_total},%{http_code}\n" "$url"
done > ttfb-report.csv

Seguire la catena di redirect

I redirect multipli rallentano il rendering e aumentano la latenza percepita, specialmente su mobile dove ogni hop richiede un nuovo DNS lookup. Questo comando mostra ogni hop.

curl -sIL -o /dev/null -w "%{url_effective}\n" https://example.com

Per vedere tutti gli hop con i rispettivi status code:

curl -sIL https://example.com 2>&1 | grep -E "^(HTTP/|Location:)"

Output esempio:

HTTP/2 301
Location: https://www.example.com/
HTTP/2 200

Interpretazione SEO — Evoluzione della posizione di Google sui redirect e PageRank:

La questione “i redirect perdono link equity?” ha una storia lunga e spesso fraintesa:

  • Pre-2013: Era ampiamente accettato che i 301 causassero una perdita di PageRank. Matt Cutts (allora Head of Web Spam, Google) confermò in un video ufficiale Webmasters: “The amount of PageRank that dissipates through a 301 is currently identical to the amount of PageRank that dissipates through a link” — ovvero il decay fisiologico di qualsiasi link, non una penalità aggiuntiva.
  • Luglio 2016: Gary Illyes (Google Webmaster Trends Analyst) dichiarò via Twitter che qualsiasi redirect 30x (301, 302, 3xx) non causa più alcuna perdita di PageRank. Search Engine Land titolò: “Google: There is no PageRank dilution when using 301, 302, or 30x redirects anymore”.
  • 2022: John Mueller (Google Search Advocate) ribadì il concetto, aggiungendo che per massimizzare il passaggio di segnali è importante aggiornare i link interni che puntano ancora alla vecchia URL.
  • Stato attuale (2026): Google usa i redirect come segnale di canonicalizzazione. Il PageRank viene consolidato sulla URL canonica, non disperso.

Conclusione pratica: Le catene di redirect vanno ridotte al minimo (best practice: massimo 1 hop), ma per ragioni di crawl budget, latenza utente (specialmente su mobile, dove ogni hop richiede un nuovo DNS lookup) e semplicità di manutenzione — non per perdita di link equity.

Simulare user-agent specifici

Fondamentale per verificare cloaking e rendering differenziato.

# Simulare Googlebot Desktop
curl -sI -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://example.com

# Simulare Googlebot Smartphone
# NOTA: la versione Chrome (W.X.Y.Z) si aggiorna automaticamente con Googlebot "evergreen".
# Per la stringa UA corrente, consultare:
# https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers
curl -sI -A "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/W.X.Y.Z Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://example.com

# Simulare Bingbot
curl -sI -A "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" https://example.com

# Confrontare risposte tra user-agent (Googlebot vs browser reale)
diff <(curl -s -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://example.com | head -100) \
     <(curl -s -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/131.0.0.0 Safari/537.36" https://example.com | head -100)

Caso d’uso SEO: Se le risposte differiscono significativamente tra Googlebot e un browser reale, potrebbe esserci cloaking — una violazione delle linee guida di Google. Attenzione: questo test verifica solo la risposta server-side all’UA; per il cloaking basato su IP è necessaria un’analisi diversa.

Verificare la compressione

La compressione riduce il peso delle pagine e migliora LCP.

# Verificare supporto gzip/brotli
curl -sI -H "Accept-Encoding: gzip, deflate, br" https://example.com | grep -i content-encoding

# Confrontare dimensione con e senza compressione
echo "Compressa: $(curl -s --compressed https://example.com | wc -c) bytes"
echo "Non compressa: $(curl -s https://example.com | wc -c) bytes"

1.2 wget — Download ricorsivo e mirroring

Creare un mirror locale del sito per analisi

wget --mirror \
     --convert-links \
     --adjust-extension \
     --page-requisites \
     --no-parent \
     --wait=1 \
     --random-wait \
     --limit-rate=500k \
     -e robots=off \
     -U "Mozilla/5.0" \
     https://example.com

Parametri spiegati:

  • --mirror — Attiva download ricorsivo con timestamp, necessario per analisi strutturale completa.
  • --convert-links — Converte i link assoluti in relativi, utile per navigare il sito offline.
  • --page-requisites — Scarica CSS, JS, immagini: essenziale per analizzare il peso reale delle pagine.
  • --wait=1 --random-wait — Pausa casuale tra le richieste per non sovraccaricare il server.
  • --limit-rate=500k — Limita la banda. Importante per siti di clienti: non saturare le loro risorse.

Limite: Come curl, wget scarica solo l’HTML iniziale. I contenuti generati da JavaScript non saranno presenti nel mirror.

Estrarre tutti gli URL di un sito

wget --spider --recursive --no-verbose --output-file=crawl.log https://example.com
grep -oP 'https?://[^\s]+' crawl.log | sort -u > all-urls.txt

Verificare link rotti in blocco

wget --spider --recursive --level=3 --no-verbose --output-file=spider.log https://example.com
grep -B2 "broken link" spider.log

1.3 ping e traceroute — Diagnostica di rete

Misurare la latenza del server

# Latenza base
ping -c 10 example.com

# Salvare statistiche
ping -c 100 example.com | tail -1
# Output: rtt min/avg/max/mdev = 12.345/15.678/23.456/3.210 ms

Interpretazione SEO: Latenza media >50ms per utenti nella stessa regione geografica suggerisce un hosting inadeguato o la necessità di una CDN.

Tracciare il percorso di rete

# Traceroute standard
traceroute example.com

# Con risoluzione DNS disabilitata (più veloce)
traceroute -n example.com

# Versione moderna con MTR (My TraceRoute) — combina ping e traceroute
mtr --report --report-cycles 10 example.com

Output MTR esempio:

HOST                   Loss%   Snt   Last   Avg   Best  Wrst  StDev
1. gateway.local        0.0%    10    1.2   1.5   1.0   3.2   0.7
2. isp-router.net       0.0%    10   12.3  13.1  11.5  18.2   2.1
3. cdn-edge.example     0.0%    10   15.6  16.2  14.8  22.1   2.3

Caso d’uso SEO: Identifica colli di bottiglia nella rete tra utente e server. Utile per giustificare l’adozione di una CDN a un cliente. In un caso reale, l’analisi MTR ha permesso di isolare 400ms di latenza introdotti da un hop su un peering intermedio, risolvibili spostando il PoP della CDN.

1.4 ab, siege e alternative — Test di carico

Apache Benchmark

# 1000 richieste con 10 connessioni concorrenti
ab -n 1000 -c 10 -H "Accept-Encoding: gzip" https://example.com/

# Output chiave:
# Requests per second: indica la capacità del server
# Time per request: deve restare sotto 500ms per buona UX
# Transfer rate: velocità effettiva di trasferimento

Nota: ab richiede supporto SSL compilato per URL HTTPS. Verificare con ab -h 2>&1 | grep -i ssl. Se non disponibile, usare alternative con supporto HTTPS nativo:

# hey (Go-based, supporto HTTPS nativo)
# Installare: go install github.com/rakyll/hey@latest
hey -n 1000 -c 10 https://example.com/

# wrk (benchmark HTTP ad alte prestazioni)
wrk -t4 -c10 -d30s https://example.com/

Siege — Test di carico con URL multipli

# Creare file con URL da testare
cat > urls-test.txt << 'EOF'
https://example.com/
https://example.com/chi-siamo
https://example.com/servizi
https://example.com/blog
EOF

# Test con 25 utenti concorrenti per 1 minuto
siege -c 25 -t 1M -f urls-test.txt

# Output chiave:
# Availability: deve essere 100% — drop indicano problemi di capacità
# Response time: tempo medio di risposta sotto carico
# Transaction rate: transazioni al secondo

Caso d’uso SEO: Simula cosa succede quando Googlebot effettua crawl intensivo. Se il server non regge, perde pagine nell’indice. In un audit reale, un test con siege ha evidenziato un drop di availability al 78% con soli 50 utenti concorrenti, causato da un pool di connessioni MySQL sottodimensionato.


2. Analisi DNS e Configurazione Dominio

La configurazione DNS è il livello infrastrutturale che precede qualsiasi interazione HTTP. Un DNS lento aggiunge latenza a ogni richiesta — incluso il TTFB misurato nella sezione precedente. Una configurazione errata dei record CNAME, A o delle delegation può causare problemi di canonicalizzazione tra varianti www e non-www che impattano l’indicizzazione. I comandi di questa sezione permettono di ispezionare, validare e monitorare la configurazione DNS di qualsiasi dominio.

2.1 dig — Query DNS avanzate

Verificare tutti i record DNS rilevanti per SEO

# Record A (indirizzo IPv4)
dig +short A example.com

# Record AAAA (indirizzo IPv6)
dig +short AAAA example.com

# Record CNAME
dig +short CNAME www.example.com

# Record MX (mail — rilevante per email deliverability e reputazione dominio)
dig +short MX example.com

# Record TXT (SPF, DKIM, DMARC, site verification)
dig +short TXT example.com

# Record NS (nameserver)
dig +short NS example.com

# Record SOA (Start of Authority)
dig +short SOA example.com

# Record CAA (Certificate Authority Authorization)
dig +short CAA example.com

Verificare la propagazione DNS globale

# Interrogare DNS pubblici specifici
dig @8.8.8.8 example.com        # Google DNS
dig @1.1.1.1 example.com        # Cloudflare DNS
dig @208.67.222.222 example.com  # OpenDNS

# Verificare TTL residuo (colonna 2 dell'output)
dig example.com | awk '/^example/ {print "TTL:", $2, "secondi"}'

Interpretazione SEO: TTL troppo bassi (<300s) causano lookup DNS frequenti che rallentano il TTFB. TTL troppo alti (>86400s) rallentano le migrazioni. Un TTL tra 3600s e 14400s è generalmente il compromesso migliore.

Verificare configurazione DNSSEC

dig +dnssec example.com | grep -E "RRSIG|DNSKEY"

2.2 nslookup — Risoluzione rapida

# Risoluzione diretta
nslookup example.com

# Reverse DNS (da IP a hostname)
nslookup 93.184.216.34

# Verificare se il reverse DNS corrisponde (importante per email reputation)
host $(dig +short example.com)

2.3 whois — Informazioni registrazione dominio

# Dati completi del dominio
whois example.com

# Estrarre solo le date chiave
whois example.com | grep -iE "creation|expir|updated|registrar"

Output esempio:

Creation Date: 1995-08-14T04:00:00Z
Updated Date: 2024-08-14T07:01:44Z
Registry Expiry Date: 2025-08-13T04:00:00Z
Registrar: EXAMPLE REGISTRAR

Interpretazione SEO — La verità sull’età del dominio:

L’idea che “domini più vecchi si posizionano meglio” è uno dei miti SEO più persistenti. Google lo ha negato in più occasioni:

  • 2010: Matt Cutts (Head of Web Spam, Google) dichiarò in un video ufficiale: “The difference between a domain that’s six months old versus one year old is really not that big at all”.
  • 2019-2022: John Mueller (Google Search Advocate) fu ancora più esplicito, affermando che l’età del dominio ha “zero SEO benefits” e che Google non la utilizza come fattore di ranking.
  • 2024: Un data leak interno di Google rivelò l’esistenza di un attributo hostAge nel codice, riaccendendo il dibattito. Tuttavia, Google ha chiarito che non tutti gli attributi presenti nel codice sono utilizzati attivamente nel ranking.

La correlazione tra età e posizionamento esiste (domini più vecchi hanno avuto più tempo per accumulare backlink, contenuti e autorità), ma non è causalità. Uno studio Adilo su 2.000 keyword (2025) ha confermato che domini più giovani con contenuti migliori superano regolarmente domini più vecchi.

  • Creation Date — Utile come segnale contestuale nell’analisi competitiva e nella due diligence di domini acquisiti. Non è un fattore di ranking diretto.
  • Expiry Date — Utile per verificare che il dominio non sia in scadenza imminente (rischio operativo). Nessuna evidenza confermata di impatto diretto sul ranking, nonostante un vecchio brevetto Google (2005) suggerisse che domini registrati per periodi lunghi potessero essere considerati più legittimi.
  • Registrar — Informazione utile per la due diligence su domini acquisiti. Registrar specifici possono essere associati a pattern di spam in analisi forensi.

Controllo bulk di domini competitori

for domain in competitor1.com competitor2.com competitor3.com; do
  echo "=== $domain ==="
  whois "$domain" | grep -iE "creation|expir"
done

3. Analisi dei Contenuti e Struttura del Sito

L’analisi dei contenuti è il cuore dell’audit on-page. I comandi di questa sezione replicano ciò che Googlebot “vede” quando processa una pagina: struttura degli heading, meta tag, immagini, link interni ed esterni, dati strutturati. La distinzione tra Initial HTML e Rendered DOM (approfondita nella sotto-sezione 3.0) è il concetto più critico: determina se i comandi basati su curl sono sufficienti o se serve un headless browser. Per un’analisi complementare lato browser, consultare la guida SEO ai DevTools di Google Chrome.

3.0 Initial HTML vs Rendered DOM — Premessa fondamentale

Questo è il concetto più importante dell’intera sezione. curl (e wget) recuperano esclusivamente l’Initial HTML restituito dal server. Nel web moderno, dominato da framework JavaScript (React, Vue, Angular, Next.js CSR, Astro islands), il contenuto visibile all’utente — e quello che Googlebot indicizza dopo il rendering — può essere radicalmente diverso dall’HTML iniziale.

Contesto Googlebot: Dal 2019, Googlebot utilizza una versione “evergreen” di Chrome per il rendering JavaScript (annuncio Google I/O 2019, confermato da Martin Splitt, Developer Advocate Google). Tuttavia, il rendering avviene in una seconda fase (Web Rendering Service), potenzialmente con ritardo. Per il SEO è quindi cruciale sapere cosa c’è nell’HTML iniziale (che viene processato immediatamente) vs cosa richiede rendering JS (che entra in una coda separata).

Regola: Prima di analizzare qualsiasi sito con curl, verifica la modalità di rendering. Se il sito usa CSR, i comandi basati su curl + grep restituiranno un DOM vuoto o parziale.

Verificare se il contenuto è nel source HTML

# Se questo restituisce il testo atteso, il sito è SSR/statico: curl basta
curl -s https://example.com | grep -c "testo-visibile-nella-pagina"

# Se restituisce 0, il contenuto è renderizzato via JS: serve Headless Chrome

Estrarre il DOM renderizzato via Headless Chrome

# Metodo 1: Headless Chrome nativo (richiede Chrome/Chromium installato)
google-chrome --headless --disable-gpu --dump-dom https://example.com 2>/dev/null | grep -oiP '<title>.*?</title>'

# Metodo 2: Puppeteer CLI one-liner (richiede Node.js)
npx puppeteer-cli screenshot --url https://example.com --html > rendered.html

# Metodo 3: Playwright (alternativa cross-browser)
npx playwright-cli pdf https://example.com rendered.pdf

Nota per l’audit: Quando analizzi un sito client, il primo step è sempre determinare la strategia di rendering (SSR, CSR, SSG, ISR). Questo determina se curl è sufficiente o se serve un Headless browser.

3.1 Analisi dell’HTML e struttura heading

Estrarre la gerarchia degli heading (H1-H6) — metodo robusto

Analizzare HTML con regex (grep -oiP) è notoriamente fragile: basta un attributo multilinea, un commento HTML o un tag annidato per rompere l’output. Per un audit professionale, utilizza parser HTML dedicati.

Metodo consigliato: pup (parser CSS selector da CLI)

# Installare pup: go install github.com/ericchiang/pup@latest
# oppure: brew install pup (macOS)

# Estrarre tutti gli heading con testo
curl -s https://example.com | pup 'h1, h2, h3, h4, h5, h6 text{}'

# Estrarre heading con il tag di livello
curl -s https://example.com | pup 'h1, h2, h3, h4, h5, h6'

# Estrarre solo H1
curl -s https://example.com | pup 'h1 text{}'

Metodo alternativo con htmlq (se pup non disponibile):

# Installare: cargo install htmlq
curl -s https://example.com | htmlq 'h1, h2, h3' --text

Metodo fallback con grep (solo per SSR/HTML semplice):

curl -s https://example.com | grep -oiP '<h[1-6][^>]*>.*?</h[1-6]>' | sed 's/<[^>]*>//g'

Per un output strutturato con indentazione gerarchica:

curl -s https://example.com | grep -oiP '<h[1-6][^>]*>.*?</h[1-6]>' | \
  while IFS= read -r line; do
    level=$(echo "$line" | grep -oP '(?i)<h\K[1-6]')
    text=$(echo "$line" | sed 's/<[^>]*>//g' | xargs)
    indent=$(printf '%*s' $((level * 2)) '')
    echo "${indent}H${level}: $text"
  done

Caso d’uso SEO: Verifica che esista un solo H1, che la gerarchia sia logica (non H1 > H3 saltando H2), e che i titoli contengano le keyword target.

Contare gli heading per livello

curl -s https://example.com | grep -oiP '<h[1-6]' | sort | uniq -c | sort -rn

Output esempio:

  1 <h1
  5 <h2
 12 <h3
  3 <h4

3.2 Analisi dei meta tag

Estrarre title e meta description — metodo robusto

# Con pup (consigliato)
curl -s https://example.com | pup 'title text{}'
curl -s https://example.com | pup 'meta[name="description"] attr{content}'
curl -s https://example.com | pup 'link[rel="canonical"] attr{href}'
curl -s https://example.com | pup 'meta[name="robots"] attr{content}'
curl -s https://example.com | pup 'link[hreflang] attr{hreflang}'
curl -s https://example.com | pup 'meta[property^="og:"] json{}'

# Fallback con grep (funziona su HTML semplice/SSR)
curl -s https://example.com | grep -oiP '<title[^>]*>.*?</title>' | sed 's/<[^>]*>//g'
curl -s https://example.com | grep -oiP '<meta[^>]*name="description"[^>]*>' | grep -oP 'content="[^"]*"'
curl -s https://example.com | grep -oiP '<meta[^>]*name="robots"[^>]*>'
curl -s https://example.com | grep -oiP '<link[^>]*rel="canonical"[^>]*>' | grep -oP 'href="[^"]*"'
curl -s https://example.com | grep -oiP '<link[^>]*hreflang[^>]*>'
curl -s https://example.com | grep -oiP '<meta[^>]*property="og:[^"]*"[^>]*>'

Audit meta tag su URL multipli

while IFS= read -r url; do
  html=$(curl -s "$url")
  title=$(echo "$html" | pup 'title text{}' 2>/dev/null || echo "$html" | grep -oiP '<title>.*?</title>' | sed 's/<[^>]*>//g')
  desc=$(echo "$html" | pup 'meta[name="description"] attr{content}' 2>/dev/null || echo "$html" | grep -oiP 'name="description"[^>]*content="[^"]*"' | grep -oP 'content="\K[^"]*')
  canonical=$(echo "$html" | pup 'link[rel="canonical"] attr{href}' 2>/dev/null || echo "$html" | grep -oiP 'rel="canonical"[^>]*href="[^"]*"' | grep -oP 'href="\K[^"]*')
  title_len=${#title}
  desc_len=${#desc}
  echo "$url|$title_len|$desc_len|$title|$desc|$canonical"
done < urls.txt > meta-audit.csv

Soglie SEO per il report:

  • Title: 50-60 caratteri (ideale), >60 troncato in SERP.
  • Description: 150-160 caratteri (ideale), >160 troncata in SERP.
  • Canonical: deve puntare a sé stessa o alla versione preferita.

Nota: un BOM (Byte Order Mark) UTF-8 non rimosso nel file HTML può causare problemi di parsing dei meta tag e rendering anomalo dei primi byte della pagina. Per un approfondimento su come identificare e risolvere questa problematica, consultare l’articolo sul BOM UTF-8 nel robots.txt e nei file HTML.

3.3 Analisi delle immagini

Trovare immagini senza attributo alt

# Con pup
curl -s https://example.com | pup 'img:not([alt]) attr{src}'

# Fallback grep
curl -s https://example.com | grep -oiP '<img[^>]*>' | grep -viP 'alt="[^"]+"'

Elencare tutte le immagini con dimensioni

curl -s https://example.com | grep -oiP '<img[^>]*src="[^"]*"[^>]*>' | \
  grep -oP 'src="\K[^"]*' | while read -r img; do
    # Gestire URL relativi
    [[ "$img" != http* ]] && img="https://example.com$img"
    size=$(curl -sI "$img" | grep -i content-length | awk '{print $2}' | tr -d '\r')
    type=$(curl -sI "$img" | grep -i content-type | awk '{print $2}' | tr -d '\r')
    echo "$img | ${size:-N/A} bytes | $type"
done

Verificare immagini WebP/AVIF

# Verificare se il server serve WebP quando richiesto
curl -sI -H "Accept: image/webp" https://example.com/image.jpg | grep -i content-type

# Verificare supporto AVIF
curl -sI -H "Accept: image/avif" https://example.com/image.jpg | grep -i content-type

Caso d’uso SEO: Le immagini in formato next-gen (WebP, AVIF) riducono il peso della pagina fino all’80%, migliorando LCP e il punteggio Core Web Vitals.

3.4 Analisi dei link interni e esterni

Estrarre tutti i link da una pagina

# Con pup (robusto)
curl -s https://example.com | pup 'a attr{href}' | sort -u

# Solo link interni
curl -s https://example.com | pup 'a attr{href}' | grep -i "example.com" | sort -u

# Solo link esterni
curl -s https://example.com | pup 'a attr{href}' | grep -P '^https?://' | grep -vi "example.com" | sort -u

# Fallback grep
curl -s https://example.com | grep -oiP 'href="[^"]*"' | sed 's/href="//;s/"//' | sort -u

# Link con attributo nofollow
curl -s https://example.com | grep -oiP '<a[^>]*rel="[^"]*nofollow[^"]*"[^>]*href="[^"]*"'

Per tecniche di ricerca avanzata basate su operatori Google, che complementano l’analisi dei link da terminale con la verifica diretta dell’indice, consultare la guida al Google Dorking.

Contare link interni vs esterni

html=$(curl -s https://example.com)
internal=$(echo "$html" | grep -oiP 'href="[^"]*"' | grep -ci "example.com")
external=$(echo "$html" | grep -oiP 'href="https?://[^"]*"' | grep -cvi "example.com")
echo "Link interni: $internal | Link esterni: $external | Ratio: $(echo "scale=2; $internal/$external" | bc)"

3.5 Analisi dei dati strutturati (Schema.org)

Estrarre JSON-LD

curl -s https://example.com | grep -oiP '<script type="application/ld\+json">.*?</script>' | \
  sed 's/<script type="application\/ld+json">//g;s/<\/script>//g' | python3 -m json.tool

Verificare la presenza di Schema specifici

curl -s https://example.com | grep -oiP '"@type"\s*:\s*"[^"]*"' | sort -u

Output esempio:

"@type": "Organization"
"@type": "WebPage"
"@type": "BreadcrumbList"

Nota (2026): Ad agosto 2023 Google ha drasticamente ridotto la visibilità dei FAQ Rich Results in SERP. L’annuncio ufficiale (Google Search Central Blog, agosto 2023) specificava che i risultati FAQ sarebbero stati mostrati “only for well-known, authoritative government and health websites”. Per tutti gli altri siti, il markup FAQPage viene ancora letto ma non genera più il rich snippet espanso. Questa modifica ha avuto un impatto significativo su CTR e traffico per molti siti che dipendevano dai FAQ snippet. Schema ancora attivi e con rich results confermati: HowTo, Product, LocalBusiness, Article, BreadcrumbList, Review, Event.


4. Crawling e Indicizzazione

Le verifiche di crawling e indicizzazione rappresentano il passaggio dall’analisi ‘statica’ del sito all’analisi di come Googlebot interagisce effettivamente con le pagine. Controllare robots.txt, sitemap XML e direttive meta robots da terminale permette di verificare direttamente — senza intermediazioni di tool terzi — cosa il crawler può raggiungere e cosa gli è precluso. L’analisi dei log del server (Sezione 7, approfondita nell’articolo dedicato all’analisi log e negative SEO) fornisce poi la verifica empirica del comportamento reale di Googlebot.

4.1 Analisi robots.txt

Scaricare e analizzare robots.txt

# Scaricare
curl -s https://example.com/robots.txt

# Verificare se una specifica URL è bloccata
curl -s https://example.com/robots.txt | grep -i "disallow" | while read -r line; do
  pattern=$(echo "$line" | awk '{print $2}')
  echo "Bloccato: $pattern"
done

# Estrarre le sitemap dichiarate
curl -s https://example.com/robots.txt | grep -i "sitemap:" | awk '{print $2}'

Confrontare robots.txt nel tempo

# Salvare una copia datata
curl -s https://example.com/robots.txt > "robots_$(date +%Y%m%d).txt"

# Confrontare con versione precedente
diff robots_20260101.txt robots_20260201.txt

4.2 Analisi Sitemap XML

Scaricare e contare URL nella sitemap

# Scaricare la sitemap
curl -s https://example.com/sitemap.xml > sitemap.xml

# Contare le URL
grep -c "<loc>" sitemap.xml

# Estrarre tutte le URL
grep -oP '<loc>\K[^<]*' sitemap.xml

# Estrarre URL con lastmod
paste <(grep -oP '<loc>\K[^<]*' sitemap.xml) <(grep -oP '<lastmod>\K[^<]*' sitemap.xml)

Analizzare sitemap index (sitemap di sitemap)

# Estrarre le sotto-sitemap
curl -s https://example.com/sitemap_index.xml | grep -oP '<loc>\K[^<]*' | while read -r sitemap; do
  count=$(curl -s "$sitemap" | grep -c "<loc>")
  echo "$sitemap: $count URLs"
done

Verificare che tutte le URL della sitemap rispondano 200

grep -oP '<loc>\K[^<]*' sitemap.xml | while read -r url; do
  status=$(curl -o /dev/null -s -w "%{http_code}" "$url")
  [[ "$status" != "200" ]] && echo "$status $url"
done > sitemap-errors.txt

Caso d’uso SEO: URL non-200 nella sitemap sprecano crawl budget e inviano segnali negativi a Google. Questo audit identifica immediatamente i problemi.

4.3 Verifica indicizzazione

Controllare la meta tag robots e X-Robots-Tag

# Meta robots nell'HTML
curl -s https://example.com/pagina | grep -oiP '<meta[^>]*name="robots"[^>]*>'

# X-Robots-Tag nell'header HTTP
curl -sI https://example.com/pagina | grep -i "x-robots-tag"

# Controllo bulk
while read -r url; do
  meta=$(curl -s "$url" | grep -oiP 'name="robots"[^>]*content="\K[^"]*')
  header=$(curl -sI "$url" | grep -i "x-robots-tag" | awk '{print $2}' | tr -d '\r')
  echo "$url | meta: ${meta:-none} | header: ${header:-none}"
done < urls.txt

4.4 Gestione del crawl budget

Misurare il tempo di crawl per sezione

sections=("/" "/blog/" "/prodotti/" "/servizi/" "/chi-siamo/")
for section in "${sections[@]}"; do
  ttfb=$(curl -o /dev/null -s -w "%{time_starttransfer}" "https://example.com${section}")
  size=$(curl -s "https://example.com${section}" | wc -c)
  echo "Sezione: $section | TTFB: ${ttfb}s | Size: $size bytes"
done

5. Analisi degli Header HTTP

Gli header HTTP sono la ‘conversazione invisibile’ tra server e client che determina caching, sicurezza, redirect e performance — tutti fattori che impattano l’esperienza utente e il comportamento del crawler. Un header Cache-Control mal configurato spreca banda e rallenta il re-crawling; un header HSTS mancante espone a downgrade attack; un Vary errato invalida la cache CDN. Per una trattazione completa degli header HTTP nel contesto SEO, consultare la guida tecnica alle intestazioni HTTP.

5.1 Header di caching

curl -sI https://example.com | grep -iE "cache-control|expires|etag|last-modified|age|vary|cf-cache"

Header e significato SEO:

HeaderSignificato SEO
Cache-Control: max-age=31536000Risorsa cacheable per 1 anno. Ideale per asset statici (CSS, JS, immagini).
Cache-Control: no-cacheLa risorsa può essere memorizzata in cache, ma deve essere rivalidata con il server a ogni utilizzo tramite ETag o If-Modified-Since (RFC 7234, sezione 5.2.2.2). Diverso da no-store. Errore comune: confondere no-cache con “non memorizzare” — in realtà il browser conserva la copia, la rivalidata prima di servirla.
Cache-Control: no-storeMai memorizzare. Usare solo per dati sensibili (pagine con dati personali, aree riservate).
ETagIdentificatore univoco della risorsa. Abilita caching condizionale efficiente con rivalidazione 304.
Vary: Accept-EncodingIndica che la risposta varia per encoding. Necessario per corretta cache con gzip/brotli e CDN.
CF-Cache-Status: HITLa risorsa è servita dalla CDN Cloudflare. Riduce il TTFB.

5.2 Header di sicurezza

curl -sI https://example.com | grep -iE "strict-transport|content-security|x-frame|x-content-type|referrer-policy|permissions-policy|x-xss"

Controllo completo degli header di sicurezza:

url="https://example.com"
headers=$(curl -sI "$url")

check_header() {
  local name="$1"
  if echo "$headers" | grep -qi "$name"; then
    echo "[OK]  $name: $(echo "$headers" | grep -i "$name" | head -1 | cut -d: -f2-)"
  else
    echo "[MISS] $name: non presente"
  fi
}

check_header "Strict-Transport-Security"
check_header "Content-Security-Policy"
check_header "X-Frame-Options"
check_header "X-Content-Type-Options"
check_header "Referrer-Policy"
check_header "Permissions-Policy"

Per un approfondimento su come i cookie impattano tracking, privacy e conformità normativa, e su come verificarne il comportamento tramite header HTTP, consultare la guida tecnica ai cookie.

5.3 Header di redirect e canonicalizzazione

# Verificare redirect da HTTP a HTTPS
curl -sI http://example.com | head -5

# Verificare redirect www vs non-www
curl -sI http://www.example.com | head -5
curl -sI http://example.com | head -5

# Test completo delle 4 varianti
for variant in "http://example.com" "https://example.com" "http://www.example.com" "https://www.example.com"; do
  final=$(curl -sIL -o /dev/null -w "%{url_effective}" "$variant")
  echo "$variant => $final"
done

Caso d’uso SEO: Tutte e 4 le varianti devono convergere su un’unica versione canonica (tipicamente https://www.example.com o https://example.com) con redirect 301.

5.4 Header di performance

# Verificare HTTP/2 o HTTP/3
curl -sI --http2 https://example.com | head -1

# Verificare supporto HTTP/3 tramite header Alt-Svc
curl -sI https://example.com | grep -i "alt-svc"
# Output atteso per HTTP/3: alt-svc: h3=":443"; ma=86400

# Verificare risorse con preload hint
curl -sI https://example.com | grep -i "link:" | grep "preload"

# Verificare 103 Early Hints (sostituto di HTTP/2 Server Push, deprecato in Chrome 106)
curl -sI https://example.com | grep -i "103"

# Header specifici CDN
curl -sI https://example.com | grep -iE "x-served-by|x-cache|server|via|cf-ray"

Nota (2026): HTTP/2 Server Push è stato rimosso da Chrome 106 (settembre 2022) dopo che i dati di utilizzo mostrarono un adoption rate inferiore all’1% e performance peggiori delle alternative nella maggior parte dei casi reali. L’intent message di Chrome (2022) citava: “No evidence of processing the server push responses” nella maggioranza dei siti monitorati. Le alternative moderne sono:

  • <link rel="preload"> nell’HTML — per risorse critiche note a priori (font, hero image, CSS critico).
  • 103 Early Hints (RFC 8297) nell’header HTTP — supportato da Cloudflare (dal 2022), Fastly e Apache/Nginx recenti. Permette al browser di iniziare il preload prima che il server completi la generazione della risposta HTML.

6. Verifiche di Sicurezza

Le verifiche di sicurezza sono parte integrante di un audit tecnico SEO, non un extra opzionale. Un sito compromesso viene segnalato da Google Safe Browsing e desindicizzato; un certificato SSL scaduto blocca il crawling; protocolli TLS obsoleti aggiungono latenza all’handshake. Queste verifiche rientrano nel framework più ampio della SEO tecnica, dove sicurezza e accessibilità sono prerequisiti non negoziabili per il posizionamento.

6.1 Analisi certificato SSL/TLS

Dettagli certificato completi

echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -text | grep -E "Issuer:|Not Before:|Not After:|Subject:|DNS:"

Verificare la scadenza del certificato

echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | \
  openssl x509 -noout -dates

Output esempio:

notBefore=Jan  1 00:00:00 2026 GMT
notAfter=Apr  1 23:59:59 2026 GMT

Script di monitoraggio scadenza certificati

domains=("example.com" "shop.example.com" "blog.example.com")
for domain in "${domains[@]}"; do
  expiry=$(echo | openssl s_client -servername "$domain" -connect "$domain":443 2>/dev/null | \
    openssl x509 -noout -enddate | cut -d= -f2)
  days_left=$(( ($(date -d "$expiry" +%s) - $(date +%s)) / 86400 ))
  status="OK"
  [[ $days_left -lt 30 ]] && status="WARNING"
  [[ $days_left -lt 7 ]] && status="CRITICAL"
  echo "[$status] $domain: scade il $expiry ($days_left giorni)"
done

Verificare la catena di certificati

echo | openssl s_client -showcerts -servername example.com -connect example.com:443 2>/dev/null | \
  awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{print}' | \
  openssl x509 -noout -subject -issuer

Verificare i protocolli TLS supportati

for proto in ssl3 tls1 tls1_1 tls1_2 tls1_3; do
  result=$(echo | openssl s_client -"$proto" -connect example.com:443 2>&1)
  if echo "$result" | grep -q "CONNECTED"; then
    echo "[ATTIVO] $proto"
  else
    echo "[DISABILITATO] $proto"
  fi
done

Interpretazione SEO: TLS 1.0 e 1.1 sono stati formalmente deprecati dall’IETF con la RFC 8996 (marzo 2021). Tutti i principali browser li hanno disabilitati: Chrome 84 (luglio 2020), Firefox 78, Safari 13.1. I siti che ancora li espongono mostrano un warning “Not Secure” e rischiano problemi di compatibilità. Solo TLS 1.2 e 1.3 devono restare attivi. TLS 1.3 (RFC 8446, agosto 2018) è preferibile per il minor overhead sull’handshake (1-RTT vs 2-RTT di TLS 1.2, 0-RTT in sessioni riprese), con impatto misurabile sul TTFB — tipicamente 50-100ms di risparmio per connessione.

6.2 Analisi con nmap

Scan delle porte aperte

# Scan rapido delle porte comuni
nmap -F example.com

# Scan delle porte web con versione servizi
nmap -sV -p 80,443,8080,8443 example.com

# Identificare il server web
nmap -sV --script=http-server-header -p 443 example.com

Caso d’uso SEO: Porte aperte non necessarie (come database o admin panels esposti) sono vulnerabilità. Un sito compromesso viene rapidamente desindicizzato da Google (Safe Browsing).

Verificare le cipher suite TLS

nmap --script ssl-enum-ciphers -p 443 example.com

6.3 Verifica HSTS e preload

# Verificare header HSTS
curl -sI https://example.com | grep -i "strict-transport-security"

# Output ideale:
# Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

# Controllare la preload list
curl -s "https://hstspreload.org/api/v2/status?domain=example.com"

Parametri HSTS consigliati per SEO:

  • max-age=63072000 — 2 anni (63.072.000 secondi), il minimo richiesto per l’inclusione nella preload list di Chrome.
  • includeSubDomains — Protegge tutti i sottodomini. Obbligatorio per la preload list.
  • preload — Richiede l’inclusione nella preload list, che è condivisa tra Chrome, Firefox, Safari, Edge e Opera. Una volta incluso, il browser non tenterà mai una connessione HTTP al dominio — la protezione è hardcoded nel browser stesso.

Attenzione: L’inclusione nella preload list è quasi irreversibile (la rimozione richiede mesi). Assicurarsi che l’intero dominio e tutti i sottodomini siano pronti per HTTPS prima di attivare preload.

6.4 Verifica contenuti misti (Mixed Content)

# Cercare risorse HTTP in pagine HTTPS
curl -s https://example.com | grep -oiP '(src|href|action)="http://[^"]*"'

Caso d’uso SEO: I contenuti misti (risorse HTTP in pagine HTTPS) causano warning nel browser, riducono il trust e possono bloccare il rendering di risorse critiche.


7. Analisi dei Log del Server

I log del server sono la prova empirica di tutto ciò che si è ipotizzato nelle sezioni precedenti. Mostrano esattamente come Googlebot ha interagito con il sito: quali URL ha crawlato, quali ha ignorato, dove ha trovato errori, con quale frequenza è tornato. L’analisi dei log è ciò che differenzia un audit basato su ipotesi da un audit basato su dati. Per un approfondimento completo sulla metodologia, compresa la segmentazione per bot e l’incrocio con i dati GSC, consultare l’articolo dedicato all’analisi log e negative SEO.

7.1 Analisi dei log di accesso

Estrarre i crawl di Googlebot — con validazione IP

Filtrare i log basandosi esclusivamente sulla stringa User-Agent è una pratica incompleta. Fino al 30% del traffico che dichiara di essere “Googlebot” è costituito da scraper, fake bot o tool SEO che inquinano l’analisi del crawl budget.

Step 1 — Filtro base (solo User-Agent):

# Filtrare le richieste che dichiarano di essere Googlebot
grep "Googlebot" /var/log/nginx/access.log

# Contare richieste per status code
grep "Googlebot" /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c | sort -rn

# URL più richieste da Googlebot
grep "Googlebot" /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20

# Frequenza di crawl nel tempo (per ora)
grep "Googlebot" /var/log/nginx/access.log | awk '{print $4}' | cut -d: -f1-2 | sort | uniq -c

Step 2 — Validazione IP (differenzia l’esperto dal principiante):

Google pubblica la lista ufficiale dei range IP di Googlebot in formato JSON. Incrociare i log con questa lista elimina i fake bot.

# Scaricare la lista ufficiale degli IP di Googlebot
curl -s https://developers.google.com/search/apis/ipranges/googlebot.json | \
  jq -r '.prefixes[] | .ipv4Prefix // .ipv6Prefix' > google_ips.txt

# Estrarre gli IP unici che dichiarano "Googlebot" nei log
grep "Googlebot" /var/log/nginx/access.log | awk '{print $1}' | sort -u > claimed_googlebot_ips.txt

# Metodo Reverse DNS: validare un singolo IP
host 66.249.66.1
# Output atteso: 1.66.249.66.in-addr.arpa domain name pointer crawl-66-249-66-1.googlebot.com.
# Se il reverse DNS non contiene "googlebot.com" o "google.com", è un fake.

# Validazione bulk tramite rDNS
while read -r ip; do
  rdns=$(host "$ip" 2>/dev/null | awk '{print $NF}')
  if echo "$rdns" | grep -qE "(googlebot|google)\.com\.$"; then
    echo "[REALE] $ip -> $rdns"
  else
    echo "[FAKE]  $ip -> $rdns"
  fi
done < claimed_googlebot_ips.txt

Nota: Google ha iniziato ad aggiornare le liste IP quotidianamente dal 2025 (annuncio di Gary Illyes, Google Analyst, motivato dal feedback dei grandi operatori di rete che necessitavano dati più freschi per il bot management). Precedentemente l’aggiornamento era settimanale. Mantenere un cron job per aggiornare google_ips.txt. Per Bingbot, il metodo di verifica ufficiale è analogo: reverse DNS deve risolvere a *.search.msn.com.

Analisi crawl per tutti i bot

# Identificare tutti i bot
grep -oiP '(Googlebot|Bingbot|DuckDuckBot|Baiduspider|YandexBot|Applebot|AhrefsBot|SemrushBot|MJ12bot|DotBot|GPTBot|ClaudeBot|Bytespider)[^"]*' \
  /var/log/nginx/access.log | cut -d/ -f1 | sort | uniq -c | sort -rn

Nota (2026): Aggiunti GPTBot (OpenAI), ClaudeBot (Anthropic) e Bytespider (ByteDance/TikTok) alla lista dei bot rilevanti. Secondo la telemetria HUMAN Security (report gennaio 2026), il traffico verificato da AI crawler è cresciuto del 6.900% YoY nel 2025, con oltre l’85% delle interazioni a carattere commerciale (pagine prodotto). Inoltre, il 5.7% delle richieste che dichiarano un User-Agent AI è spoofato (fonte: HUMAN Security, analisi su 16 crawler AI). La gestione dei bot AI nel robots.txt è diventata una necessità operativa per il crawl budget.

Report giornaliero del crawl budget

log="/var/log/nginx/access.log"
today=$(date +%d/%b/%Y)

echo "=== Report Crawl Budget — $today ==="
echo ""
echo "Googlebot:"
echo "  Richieste totali: $(grep "$today" "$log" | grep -c "Googlebot")"
echo "  Pagine HTML: $(grep "$today" "$log" | grep "Googlebot" | grep "text/html" | wc -l)"
echo "  Risorse (CSS/JS/img): $(grep "$today" "$log" | grep "Googlebot" | grep -cE "\.(css|js|png|jpg|gif|svg|woff)")"
echo "  Errori 4xx: $(grep "$today" "$log" | grep "Googlebot" | awk '$9 ~ /^4/' | wc -l)"
echo "  Errori 5xx: $(grep "$today" "$log" | grep "Googlebot" | awk '$9 ~ /^5/' | wc -l)"
echo ""
echo "Top 10 URL crawlate:"
grep "$today" "$log" | grep "Googlebot" | awk '{print $7}' | sort | uniq -c | sort -rn | head -10

7.2 Analisi degli errori

Top pagine con errori 404

awk '$9 == 404 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Errori 5xx nel tempo

awk '$9 ~ /^5/ {print $4}' /var/log/nginx/access.log | cut -d: -f1-2 | sort | uniq -c | sort -rn | head -10

Identificare pagine lente

# Per log con $request_time (Nginx)
awk '$NF > 2.0 {print $NF, $7}' /var/log/nginx/access.log | sort -rn | head -20

7.3 Analisi con awk avanzato

Report completo del traffico bot

awk '
/Googlebot/ { google++ }
/Bingbot/ { bing++ }
/AhrefsBot/ { ahrefs++ }
/SemrushBot/ { semrush++ }
/GPTBot/ { gptbot++ }
/ClaudeBot/ { claudebot++ }
{ total++ }
END {
  printf "Traffico totale: %d richieste\n", total
  printf "Googlebot:  %d (%.1f%%)\n", google, (google/total)*100
  printf "Bingbot:    %d (%.1f%%)\n", bing, (bing/total)*100
  printf "AhrefsBot:  %d (%.1f%%)\n", ahrefs, (ahrefs/total)*100
  printf "SemrushBot: %d (%.1f%%)\n", semrush, (semrush/total)*100
  printf "GPTBot:     %d (%.1f%%)\n", gptbot, (gptbot/total)*100
  printf "ClaudeBot:  %d (%.1f%%)\n", claudebot, (claudebot/total)*100
}' /var/log/nginx/access.log

8. Monitoraggio e Automazione

Le sezioni precedenti coprono l’analisi una tantum — l’audit che identifica i problemi. Il monitoraggio automatizzato è ciò che previene le regressioni. cron trasforma qualsiasi comando visto finora in un controllo schedulato; watch fornisce visibilità in tempo reale durante interventi critici (migrazioni, deploy); diff rileva cambiamenti non autorizzati al sito. La combinazione di questi strumenti trasforma il terminale da tool di analisi a sistema di early warning permanente.

8.1 cron — Automazione dei controlli SEO

Monitoraggio uptime ogni 5 minuti

# Aggiungere a crontab -e
*/5 * * * * curl -o /dev/null -s -w "%{http_code}" https://example.com | grep -q "200" || echo "$(date): SITO DOWN" >> /var/log/seo-monitor.log

Audit SEO giornaliero automatizzato

#!/bin/bash
# File: /usr/local/bin/daily-seo-audit.sh

DOMAIN="example.com"
URL="https://$DOMAIN"
LOG="/var/log/seo-audit/$(date +%Y%m%d).log"
mkdir -p /var/log/seo-audit

echo "=== SEO Audit $DOMAIN — $(date) ===" > "$LOG"

# 1. TTFB
ttfb=$(curl -o /dev/null -s -w "%{time_starttransfer}" "$URL")
echo "TTFB: ${ttfb}s" >> "$LOG"

# 2. Status code
status=$(curl -o /dev/null -s -w "%{http_code}" "$URL")
echo "Status: $status" >> "$LOG"

# 3. Certificato SSL
expiry=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN":443 2>/dev/null | \
  openssl x509 -noout -enddate | cut -d= -f2)
days_left=$(( ($(date -d "$expiry" +%s) - $(date +%s)) / 86400 ))
echo "SSL scadenza: $expiry ($days_left giorni)" >> "$LOG"

# 4. robots.txt accessibile
robots_status=$(curl -o /dev/null -s -w "%{http_code}" "$URL/robots.txt")
echo "robots.txt: $robots_status" >> "$LOG"

# 5. Sitemap accessibile
sitemap_status=$(curl -o /dev/null -s -w "%{http_code}" "$URL/sitemap.xml")
sitemap_urls=$(curl -s "$URL/sitemap.xml" | grep -c "<loc>")
echo "Sitemap: $sitemap_status ($sitemap_urls URLs)" >> "$LOG"

# 6. Compressione attiva
encoding=$(curl -sI -H "Accept-Encoding: gzip, br" "$URL" | grep -i content-encoding)
echo "Compressione: ${encoding:-MANCANTE}" >> "$LOG"

# 7. HSTS
hsts=$(curl -sI "$URL" | grep -i "strict-transport-security")
echo "HSTS: ${hsts:-MANCANTE}" >> "$LOG"

echo "=== Fine Audit ===" >> "$LOG"

# Crontab: 0 7 * * * /usr/local/bin/daily-seo-audit.sh

8.2 watch — Monitoraggio in tempo reale

# Monitorare status code in tempo reale (ogni 30 secondi)
watch -n 30 'curl -o /dev/null -s -w "Status: %{http_code} | TTFB: %{time_starttransfer}s\n" https://example.com'

# Monitorare la sitemap
watch -n 3600 'curl -s https://example.com/sitemap.xml | grep -c "<loc>"'

8.3 diff e inotifywait — Change detection

Monitorare cambiamenti al sito

#!/bin/bash
# Salva snapshot e confronta

URL="https://example.com"
DIR="/var/log/seo-snapshots"
mkdir -p "$DIR"

TODAY="$DIR/$(date +%Y%m%d).html"
YESTERDAY="$DIR/$(date -d yesterday +%Y%m%d).html"

curl -s "$URL" > "$TODAY"

if [ -f "$YESTERDAY" ]; then
  changes=$(diff "$YESTERDAY" "$TODAY" | wc -l)
  if [ "$changes" -gt 0 ]; then
    echo "$(date): $changes righe cambiate" >> "$DIR/changes.log"
    diff "$YESTERDAY" "$TODAY" > "$DIR/diff_$(date +%Y%m%d).txt"
  fi
fi

9. Manipolazione Dati e Reporting

I comandi delle sezioni precedenti producono output grezzi — testo non strutturato, header HTTP, log line, risposte JSON. awk, sed, jq, sort e uniq li trasformano in report actionable: tabelle comparative, classifiche ordinate, metriche aggregate. Queste competenze di data wrangling da terminale sono ciò che differenzia un audit professionale da una lista di screenshot.

9.1 awk — Elaborazione dati strutturati

Analizzare un export CSV di Search Console

# Top query per click (da export GSC)
awk -F'\t' 'NR>1 {print $2, $1}' Queries.csv | sort -rn | head -20

# Query con CTR basso ma impression alto (opportunità)
awk -F'\t' 'NR>1 && $3 > 1000 && $4 < 0.02 {printf "%-50s Imp: %d CTR: %.2f%% Pos: %.1f\n", $1, $3, $4*100, $5}' Queries.csv

# Raggruppare per posizione media
awk -F'\t' 'NR>1 {
  pos = int($5)
  if (pos <= 3) bucket="1-3"
  else if (pos <= 10) bucket="4-10"
  else if (pos <= 20) bucket="11-20"
  else bucket="20+"
  clicks[bucket] += $2
  imp[bucket] += $3
  count[bucket]++
}
END {
  for (b in clicks) printf "Pos %s: %d query, %d click, %d imp\n", b, count[b], clicks[b], imp[b]
}' Queries.csv

9.2 sed — Trasformazioni di testo

Pulire URL per analisi

# Rimuovere parametri UTM
sed 's/[?&]utm_[^&]*//g' urls.txt

# Rimuovere trailing slash
sed 's/\/$//' urls.txt

# Normalizzare protocollo
sed 's/^http:/https:/' urls.txt

# Estrarre path da URL completi
sed 's|https\?://[^/]*||' urls.txt

Generare regole di redirect

# Da un CSV "vecchio_url,nuovo_url" generare regole Nginx
awk -F',' '{printf "rewrite ^%s$ %s permanent;\n", $1, $2}' redirect-map.csv

# Generare .htaccess
awk -F',' '{printf "Redirect 301 %s %s\n", $1, $2}' redirect-map.csv

9.3 jq — Elaborazione dati JSON

Analizzare risposte API (es. PageSpeed Insights)

# Ottenere risultati PageSpeed Insights
curl -s "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=https://example.com&strategy=mobile&key=API_KEY" > psi.json

# Estrarre punteggi principali
jq '.lighthouseResult.categories | {
  performance: .performance.score,
  accessibility: .accessibility.score,
  best_practices: ."best-practices".score,
  seo: .seo.score
}' psi.json

# Estrarre metriche Core Web Vitals (LCP, CLS, INP)
jq '.lighthouseResult.audits | {
  FCP: .["first-contentful-paint"].displayValue,
  LCP: .["largest-contentful-paint"].displayValue,
  TBT: .["total-blocking-time"].displayValue,
  CLS: .["cumulative-layout-shift"].displayValue,
  SI: .["speed-index"].displayValue
}' psi.json

# Estrarre INP e CWV dal campo dati reali (CrUX)
jq '.loadingExperience.metrics | {
  LCP: .LARGEST_CONTENTFUL_PAINT_MS,
  INP: .INTERACTION_TO_NEXT_PAINT,
  CLS: .CUMULATIVE_LAYOUT_SHIFT_SCORE
}' psi.json

Nota importante — INP vs TBT vs FID:

La metrica di responsività ha attraversato un’evoluzione significativa:

  • Pre-marzo 2024: Il Core Web Vital per la responsività era FID (First Input Delay), che misurava solo il ritardo del primo input dell’utente.
  • Marzo 2024: Google ha ufficialmente sostituito FID con INP (Interaction to Next Paint), una metrica più completa che osserva tutte le interazioni durante l’intera visita (click, tap, keyboard) e riporta la latenza peggiore (al 75° percentile). Le soglie INP: < 200ms buono, 200-500ms da migliorare, > 500ms critico (fonte: web.dev, Google Search Central).
  • TBT (Total Blocking Time) è disponibile solo nei dati di laboratorio (Lighthouse). È un buon proxy di INP in fase di sviluppo, ma per l’assessment ufficiale dei Core Web Vitals Google usa i dati di campo (CrUX) con INP.

I tre Core Web Vitals attuali (2026) sono: LCP, INP e CLS. Il superamento dell’assessment richiede che il 75° percentile di tutte e tre le metriche sia nella soglia “buono”.

Analizzare dati strutturati JSON-LD

curl -s https://example.com | \
  grep -oP '<script type="application/ld\+json">\K.*?(?=</script>)' | \
  jq '.'

9.4 sort, uniq, cut — Pipeline di analisi

Analisi frequenze in file di log

# Top 20 pagine per numero di visite
awk '{print $7}' access.log | sort | uniq -c | sort -rn | head -20

# Distribuzione status code
awk '{print $9}' access.log | sort | uniq -c | sort -rn

# Top referrer
awk -F'"' '{print $4}' access.log | sort | uniq -c | sort -rn | head -20

# IP più attivi (possibili bot o scraper)
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20

9.5 xargs — Elaborazione parallela

Test massivo di URL

# Verificare status code di 1000 URL in parallelo (10 alla volta)
cat urls.txt | xargs -P 10 -I {} curl -o /dev/null -s -w "{} %{http_code}\n" {} > status-report.txt

# Scaricare header di tutte le pagine della sitemap
grep -oP '<loc>\K[^<]*' sitemap.xml | xargs -P 5 -I {} sh -c 'echo "=== {} ===" && curl -sI {}'

10. Strumenti Avanzati e Integrazioni API

I comandi nativi del terminale coprono la maggior parte delle verifiche di un audit tecnico. Questa sezione estende quelle capacità al livello successivo: Python per elaborazioni che superano le possibilità di awk e sed, API REST per interrogare direttamente Google Search Console e PageSpeed Insights, Lighthouse CLI per audit Core Web Vitals automatizzati, Screaming Frog in modalità headless per crawl su scala. Il terminale diventa il punto di orchestrazione di un ecosistema di strumenti professionali. Sullo stesso piano operativo, Claude Code porta un agent LLM dentro al terminale con la stessa filosofia: ho documentato configurazione e memoria di Claude Code per chi vuole capire dove la CLI conserva stato e contesto.

10.1 Python one-liner per SEO

Contare le parole di una pagina

curl -s https://example.com | python3 -c "
import sys, re
html = sys.stdin.read()
text = re.sub(r'<script[^>]*>.*?</script>', '', html, flags=re.DOTALL)
text = re.sub(r'<style[^>]*>.*?</style>', '', text, flags=re.DOTALL)
text = re.sub(r'<[^>]+>', ' ', text)
words = text.split()
print(f'Parole totali: {len(words)}')
"

Nota: Per pagine CSR/JS-rendered, sostituire curl con google-chrome --headless --dump-dom.

Estrarre tutti i link con anchor text

curl -s https://example.com | python3 -c "
import sys, re
html = sys.stdin.read()
links = re.findall(r'<a[^>]*href=\"([^\"]+)\"[^>]*>(.*?)</a>', html, re.DOTALL)
for href, text in links:
    clean_text = re.sub(r'<[^>]+>', '', text).strip()
    if clean_text:
        print(f'{clean_text}\t{href}')
"

Alternativa robusta con parser DOM:

# Con Beautiful Soup (più affidabile delle regex per HTML complesso)
curl -s https://example.com | python3 -c "
import sys
from html.parser import HTMLParser

class LinkExtractor(HTMLParser):
    def __init__(self):
        super().__init__()
        self.in_a = False
        self.href = ''
        self.text = ''
    def handle_starttag(self, tag, attrs):
        if tag == 'a':
            self.in_a = True
            self.href = dict(attrs).get('href', '')
            self.text = ''
    def handle_data(self, data):
        if self.in_a:
            self.text += data
    def handle_endtag(self, tag):
        if tag == 'a' and self.in_a:
            self.in_a = False
            t = self.text.strip()
            if t and self.href:
                print(f'{t}\t{self.href}')

parser = LinkExtractor()
parser.feed(sys.stdin.read())
"

Calcolare il rapporto testo/HTML

curl -s https://example.com | python3 -c "
import sys, re
html = sys.stdin.read()
html_size = len(html)
text = re.sub(r'<[^>]+>', '', html)
text = re.sub(r'\s+', ' ', text).strip()
text_size = len(text)
ratio = (text_size / html_size) * 100
print(f'HTML: {html_size} bytes')
print(f'Testo: {text_size} bytes')
print(f'Rapporto testo/HTML: {ratio:.1f}%')
print(f'Valutazione: {\"Buono\" if ratio > 25 else \"Da migliorare\" if ratio > 15 else \"Critico\"} (soglia: >25%)')
"

10.2 Utilizzo di API da terminale

Google Search Console API con curl

# Ottenere token OAuth2 (dopo configurazione iniziale)
# PREREQUISITO: progetto GCP con Search Console API abilitata,
# credenziali OAuth2 configurate e scope
# https://www.googleapis.com/auth/webmasters.readonly autorizzato
TOKEN=$(gcloud auth print-access-token)

# Query performance report
curl -s -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startDate": "2026-01-01",
    "endDate": "2026-01-31",
    "dimensions": ["query"],
    "rowLimit": 25000,
    "dimensionFilterGroups": [{
      "filters": [{
        "dimension": "country",
        "operator": "equals",
        "expression": "ita"
      }]
    }]
  }' \
  "https://searchconsole.googleapis.com/webmasters/v3/sites/https%3A%2F%2Fexample.com/searchAnalytics/query" | \
  jq '.rows[] | {query: .keys[0], clicks: .clicks, impressions: .impressions, ctr: .ctr, position: .position}'

Google PageSpeed Insights API

# Batch test di URL
while read -r url; do
  result=$(curl -s "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=$url&strategy=mobile&key=$API_KEY")
  score=$(echo "$result" | jq '.lighthouseResult.categories.performance.score * 100')
  lcp=$(echo "$result" | jq -r '.lighthouseResult.audits["largest-contentful-paint"].displayValue')
  cls=$(echo "$result" | jq -r '.lighthouseResult.audits["cumulative-layout-shift"].displayValue')
  echo "$url,$score,$lcp,$cls"
  sleep 2  # Rate limiting
done < urls.txt > psi-report.csv

10.3 Screaming Frog CLI (se installato)

# Crawl da riga di comando
/path/to/ScreamingFrogSEOSpider \
  --crawl https://example.com \
  --headless \
  --output-folder /reports/ \
  --export-tabs "Internal:All,Response Codes:All,Page Titles:All" \
  --save-crawl

10.4 Lighthouse CLI

# Installare Lighthouse
npm install -g lighthouse

# Audit completo
lighthouse https://example.com --output=json --output-path=./report.json --chrome-flags="--headless"

# Solo categorie specifiche
lighthouse https://example.com --only-categories=performance,seo --output=html --output-path=./seo-report.html

# Batch audit
while read -r url; do
  slug=$(echo "$url" | sed 's|https://||;s|/|_|g')
  lighthouse "$url" --only-categories=performance,seo --output=json --output-path="./${slug}.json" --chrome-flags="--headless"
  sleep 5
done < urls.txt

10.5 httpie — Alternativa moderna a curl

# Installare: pip install httpie

# Header con output colorato e leggibile
https HEAD https://example.com

# Verificare redirect
https --follow --all HEAD http://example.com

# Verificare compressione
https HEAD https://example.com Accept-Encoding:gzip,br

10.6 Comandi combinati — Script completo di audit

#!/bin/bash
# ====================================================
# SEO AUDIT COMPLETO DA TERMINALE
# ====================================================

DOMAIN="${1:-example.com}"
URL="https://$DOMAIN"
REPORT="seo-audit-${DOMAIN}-$(date +%Y%m%d).txt"

echo "============================================" > "$REPORT"
echo " SEO AUDIT: $DOMAIN" >> "$REPORT"
echo " Data: $(date)" >> "$REPORT"
echo "============================================" >> "$REPORT"

# --- PERFORMANCE ---
echo -e "\n## PERFORMANCE\n" >> "$REPORT"
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\nTotal: %{time_total}s\nSize: %{size_download} bytes\nHTTP: %{http_code}\n" "$URL" >> "$REPORT"

# --- DNS ---
echo -e "\n## DNS\n" >> "$REPORT"
echo "A: $(dig +short A $DOMAIN)" >> "$REPORT"
echo "AAAA: $(dig +short AAAA $DOMAIN)" >> "$REPORT"
echo "NS: $(dig +short NS $DOMAIN)" >> "$REPORT"
echo "MX: $(dig +short MX $DOMAIN)" >> "$REPORT"

# --- SSL ---
echo -e "\n## SSL/TLS\n" >> "$REPORT"
expiry=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN":443 2>/dev/null | \
  openssl x509 -noout -enddate | cut -d= -f2)
echo "Scadenza: $expiry" >> "$REPORT"

# --- REDIRECT ---
echo -e "\n## REDIRECT CHAIN\n" >> "$REPORT"
for v in "http://$DOMAIN" "https://$DOMAIN" "http://www.$DOMAIN" "https://www.$DOMAIN"; do
  final=$(curl -sIL -o /dev/null -w "%{url_effective}" "$v" 2>/dev/null)
  echo "$v => $final" >> "$REPORT"
done

# --- ROBOTS & SITEMAP ---
echo -e "\n## ROBOTS.TXT & SITEMAP\n" >> "$REPORT"
echo "robots.txt: $(curl -o /dev/null -s -w '%{http_code}' $URL/robots.txt)" >> "$REPORT"
echo "sitemap.xml: $(curl -o /dev/null -s -w '%{http_code}' $URL/sitemap.xml)" >> "$REPORT"
sitemap_count=$(curl -s "$URL/sitemap.xml" 2>/dev/null | grep -c "<loc>")
echo "URL in sitemap: $sitemap_count" >> "$REPORT"

# --- HEADER SICUREZZA ---
echo -e "\n## SECURITY HEADERS\n" >> "$REPORT"
headers=$(curl -sI "$URL")
for h in "Strict-Transport-Security" "Content-Security-Policy" "X-Frame-Options" "X-Content-Type-Options" "Referrer-Policy"; do
  match=$(echo "$headers" | grep -i "$h")
  if [ -n "$match" ]; then
    echo "[OK] $match" >> "$REPORT"
  else
    echo "[MANCANTE] $h" >> "$REPORT"
  fi
done

# --- COMPRESSIONE ---
echo -e "\n## COMPRESSIONE\n" >> "$REPORT"
encoding=$(curl -sI -H "Accept-Encoding: gzip, br" "$URL" | grep -i "content-encoding")
echo "${encoding:-NESSUNA COMPRESSIONE ATTIVA}" >> "$REPORT"

# --- META TAG (homepage) ---
echo -e "\n## META TAG (homepage)\n" >> "$REPORT"
html=$(curl -s "$URL")
title=$(echo "$html" | grep -oiP '<title>.*?</title>' | sed 's/<[^>]*>//g')
echo "Title: $title (${#title} caratteri)" >> "$REPORT"

echo -e "\n============================================" >> "$REPORT"
echo " Audit completato: $(date)" >> "$REPORT"
echo "============================================" >> "$REPORT"

echo "Report salvato in: $REPORT"
cat "$REPORT"

Utilizzo:

chmod +x seo-audit.sh
./seo-audit.sh example.com
./seo-audit.sh clientsite.it

Terminale e SEO: strumento complementare, non sostitutivo

Il terminale non sostituisce Screaming Frog, Google Search Console o gli altri tool commerciali dell’ecosistema SEO. Li complementa in tre aree specifiche dove nessun tool GUI può competere: verifica indipendente dei dati (i tool hanno bug, interpretazioni proprie, aggiornamenti che cambiano i risultati — il terminale restituisce il dato grezzo senza intermediazioni), automazione custom (cron + bash = monitoraggio costruito esattamente sulle esigenze del progetto, senza pagare licenze per funzionalità non utilizzate), analisi su scala di dati grezzi (log server da gigabyte, export CSV con centinaia di migliaia di righe, risposte API da elaborare in pipeline).

Il vantaggio più sottovalutato è la riproducibilità. Uno script bash è un audit documentato: descrive esattamente cosa viene verificato, come viene verificato e con quali soglie. Può essere versionato con git, condiviso con il team, eseguito su ambienti diversi, schedulato con cron. Nessun tool GUI offre questo livello di trasparenza metodologica — e in contesti enterprise, dove l’audit deve essere replicabile e verificabile da terze parti, questa trasparenza non è opzionale.

Il terminale ha limiti che è opportuno dichiarare. Non gestisce il rendering JavaScript senza un headless browser esterno (Chrome headless, Puppeteer, Playwright). Non ha una GUI per la visualizzazione dei dati — per grafici e dashboard serve esportare verso strumenti dedicati. La curva di apprendimento è ripida per chi non ha background tecnico. E per il crawling su scala (milioni di URL), tool dedicati come Screaming Frog restano più efficienti di uno spider bash artigianale.

I comandi raccolti in questa guida coprono il 90% delle verifiche tecniche di un audit SEO. Il restante 10% richiede strumenti specifici: Screaming Frog per il crawling massivo, Chrome DevTools per il debug di rendering, Google Search Console per i dati di indicizzazione e copertura. Il terminale è il collante che li unisce — estrae, trasforma, automatizza, verifica. Per il professionista SEO che lavora su architetture complesse, è uno strumento non opzionale.


Appendice A — Tabella riassuntiva comandi

ComandoCategoriaUso SEO principale
curlReteTTFB, header, redirect, compressione, API
wgetReteMirror, spider, broken links
pingReteLatenza server
traceroute / mtrReteRouting, colli di bottiglia
ab / siege / hey / wrkReteStress test, capacità server
digDNSRecord DNS, propagazione, TTL
nslookupDNSRisoluzione rapida, reverse DNS
whoisDNSEtà dominio, scadenza, registrar
pup / htmlqContenutiParsing HTML con selettori CSS
grepContenutiEstrazione pattern, meta tag, link
sedContenutiPulizia URL, trasformazioni testo
awkContenutiAnalisi CSV, log, report strutturati
jqContenutiParsing JSON, API response
opensslSicurezzaCertificati SSL, protocolli TLS
nmapSicurezzaPorte aperte, cipher suite
diffMonitoraggioChange detection, confronto versioni
cronAutomazioneAudit schedulati, monitoraggio
watchMonitoraggioControlli in tempo reale
xargsAutomazioneElaborazione parallela URL
sort / uniq / cutDatiPipeline di analisi frequenze
lighthousePerformanceAudit CWV, punteggio SEO
httpieReteAlternativa moderna a curl
google-chrome --headlessContenutiRendered DOM, analisi JS

Appendice B — Soglie di riferimento SEO (aggiornate 2026)

MetricaBuonoDa migliorareCriticoNote
TTFB≤ 800ms800ms–1.8s> 1.8sNon è un CWV. Fonte: web.dev (nov 2025)
LCP< 2.5s2.5–4.0s> 4.0sCore Web Vital. Fonte: Google Search Central
CLS< 0.10.1–0.25> 0.25Core Web Vital. Fonte: Google Search Central
INP< 200ms200–500ms> 500msCWV dal marzo 2024 (sostituisce FID)
TBT< 200ms200–600ms> 600msSolo lab data (Lighthouse), proxy di INP
FCP< 1.8s1.8–3.0s> 3.0sMetrica supplementare
Title length50–60 char30–50 / 60–70< 30 / > 70Pixel-based in SERP, ~580px
Meta desc. length150–160 char120–150< 120 / > 160Google spesso riscrive
Rapporto testo/HTML> 25%15–25%< 15%Indicativo, non fattore diretto
Redirect chain1 hop2 hop3+ hopNo perdita PageRank dal 2016 (Gary Illyes)
SSL scadenza> 30 giorni7–30 giorni< 7 giorniMonitorare con cron
Tempo risposta server< 200ms200ms–1s> 1sAudit Lighthouse

Appendice C — Strumenti da installare

ToolInstallazioneUso
pupgo install github.com/ericchiang/pup@latestParser HTML CLI con selettori CSS
htmlqcargo install htmlqAlternativa a pup (Rust)
jqapt install jqParser JSON
httpiepip install httpieHTTP client leggibile
heygo install github.com/rakyll/hey@latestBenchmark HTTP con HTTPS
mtrapt install mtrTraceroute interattivo
lighthousenpm install -g lighthouseAudit performance/SEO

Buon divertimento!

Articoli correlati

17 min lettura

L'esportazione massiva da Google Search Console a BigQuery supera i limiti dell'interfaccia nativa, garantendo retention illimitata e assenza di cap sulle righe. Configura il flusso per gestire big data SEO, storicizzare il traffico ed eseguire analisi avanzate tramite query SQL.
24 mi piace

Autore

Lascia un commento

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

Ultimi articoli aggiornati

17 min lettura

Configurare il file robots.txt secondo il Robot Exclusion Protocol permette di governare il traffico dei bot e ottimizzare il crawl budget. Analisi tecnica della sintassi e delle direttive di scansione, distinguendo il controllo del crawling dalle regole di indicizzazione noindex.
4 mi piace
54 min lettura

Superare i limiti dei tool GUI analizzando i dati grezzi da riga di comando. Utilizza pipeline CLI con curl, jq e awk per ispezionare header HTTP, log server e catene di redirect, costruendo audit SEO tecnici riproducibili e output deterministici direttamente dal terminale.
3 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 1210 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!