Ogni giorno i log del mio server registrano migliaia di scansioni automatiche alla ricerca di vulnerabilità. Le richieste sembrano minacciose:
/wp-admin/wp.php/111.php/code.php/.git/config/i.php/admin/api/.env/kal.php
La cosa che mi ha sorpreso non è stata la quantità, ma quanto poco il server sembrasse preoccuparsene. Mentre osservavo questo traffico, il carico della CPU non mostrava variazioni visibili.
L’osservazione è reale, ma la mia spiegazione iniziale era troppo assoluta. La distribuzione statica non è uno scudo magico e una 404 non è gratis. Il vantaggio concreto della mia architettura è più specifico: molte probe opportunistiche costano poco perché dietro non c’è quasi nessuna logica applicativa server-side da raggiungere.
Sono probe, non la prova di una compromissione
Vedendo /wp-admin/wp.php o /111.php viene spontaneo chiamare ogni richiesta un “exploit”. Tecnicamente è impreciso. Quello che vedo soprattutto è probing automatizzato: i bot provano nomi di file ed endpoint comuni e osservano cosa risponde.
Alcuni percorsi mirano chiaramente a WordPress o PHP. Altri, come /.git/config e /api/.env, cercano configurazioni o segreti esposti per errore. /admin è ancora più generico e può essere una route legittima. Una richiesta sospetta indica cosa sta cercando lo scanner, non che la vulnerabilità esista davvero.
Nel mio caso conta l’architettura: il sito pubblico è HTML statico prerenderizzato con Next.js e servito direttamente da Nginx.
Perché questo traffico costa poco sul mio stack
Per le pagine di cui sto parlando non c’è un runtime PHP né un database dietro ogni richiesta. Nginx serve file già esistenti. Se uno scanner chiede /111.php e il file non esiste, non parte alcuna applicazione PHP, non viene eseguito WordPress e non parte alcuna query al database. La richiesta termina semplicemente con un miss e una 404.
Questo cambia il modello di costo. In un’applicazione dinamica una richiesta può attraversare routing, framework, autenticazione, rendering, database o servizi esterni. Il mio percorso statico ha molte meno parti mobili. Nginx deve comunque accettare la connessione, processare HTTP, cercare la risorsa, scrivere il log e inviare la risposta, ma il lavoro applicativo è ridotto.
Uso anche caching aggressivo, utile per la normale distribuzione dei contenuti statici. Non attribuirei però ogni 404 casuale alla cache. Un URI inesistente mai visto può comunque passare dal normale processing di Nginx e da un lookup sul filesystem prima del 404.
La correzione importante: statico non significa “sicuro per definizione”
Questa è la parte che oggi formulerei in modo più rigoroso. Un’architettura statica rimuove molti componenti server-side dal percorso pubblico, ma non elimina il lavoro di sicurezza.
- Un file esposto resta esposto. Se
.git, un file.env, un backup o un segreto finisce nella directory pubblica, Nginx può servirlo con la stessa efficienza di un file HTML se la configurazione non lo blocca. - Nginx, TLS, sistema operativo e rete restano parte della superficie d’attacco. Vanno aggiornati e configurati correttamente.
- Il codice client può avere vulnerabilità. HTML statico non rende automaticamente sicuri JavaScript, la logica di autenticazione nel browser o gli script di terze parti.
- L’esaurimento delle risorse è ancora possibile. Connessioni, banda, handshake TLS, worker, I/O dei log e spazio disco sono finiti. Abbastanza traffico può danneggiare anche un sito statico.
La conclusione corretta quindi non è “queste richieste non contano”, ma: molte probe specifiche di una certa applicazione non trovano nulla da eseguire in questa architettura.
“Migliaia di scansioni al giorno” può sembrare più grave del carico reale
I log rendono molto visibile il rumore di fondo di Internet perché ogni probe fallita occupa una riga. Ma il totale giornaliero, da solo, non dice se il traffico sia operativamente importante. Qualche migliaio di richieste distribuite in 24 ore è molto diverso dalla stessa quantità concentrata in un breve burst.
La CPU è inoltre un solo indicatore. Nel mio caso è rimasta stabile, e questo è un buon segnale che quel traffico non stesse creando pressione di calcolo visibile in quel momento. Non dimostra che il costo fosse zero altrove. Per valutarlo seriamente guarderei anche request rate, banda, connessioni attive, worker Nginx, latenza, volume dei log e uso del disco.
Cosa ho imparato osservando questo rumore
La lezione principale per me è che l’architettura può rendere poco rilevanti intere categorie di attacchi automatizzati senza scrivere una regola per ogni firma dello scanner. Un bot può cercare backdoor WordPress e PHP per tutto il giorno; se il percorso pubblico non contiene né WordPress né PHP, quelle probe hanno ben poco da sfruttare.
Ma non confondo più “irrilevante per il mio stack” con “traffico innocuo”. La mia checklist mentale oggi è questa:
- Sapere quali runtime e servizi sono davvero raggiungibili dal percorso pubblico.
- Tenere segreti, metadata del repository, backup e build artifact fuori dal web root o bloccarli esplicitamente.
- Trattare le probe 404 ripetitive come normale rumore di Internet finché non ci sono altri segnali di targeting o impatto.
- Non decidere che il traffico abusivo è gratis guardando solo la CPU.
- Mantenere aggiornati Nginx, OS, librerie TLS e dipendenze anche quando l’applicazione è statica.
Cosa questa esperienza non dimostra
Non ho eseguito un benchmark controllato e non ho simulato un DDoS. Ho semplicemente osservato i log di produzione e il carico del server mentre arrivavano migliaia di richieste di scanner ogni giorno. È sufficiente per una conclusione pratica sul mio setup, non per la regola universale “lo statico vince sempre”.
Quello che posso confermare con precisione è questo: nel mio export statico Next.js servito da Nginx, il traffico di scanner osservato si riduceva per lo più a file miss e 404 economici invece di raggiungere un runtime PHP o un’applicazione con database. Durante l’osservazione il carico CPU è rimasto invariato.
È questo il vantaggio di resilienza che mi interessa. Meno parti mobili non rendono un sistema invulnerabile. Danno semplicemente al rumore casuale di Internet meno posti in cui trasformarsi in vero lavoro applicativo.