Hardening di Nginx su HestiaCP: come mitigare gli attacchi DDoS di Livello 7 e ottimizzare la cache dei contenuti dinamici
Come personalizzare i template Nginx di HestiaCP per limitare le richieste, bloccare le connessioni lente e attivare la FastCGI Cache, riducendo l'impatto degli attacchi DDoS applicativi e velocizzando le pagine dinamiche.
Chi gestisce un server con HestiaCP si trova prima o poi davanti a un problema comune: il sito risponde lentamente, la CPU sale alle stelle e i log di Nginx si riempiono di migliaia di richieste apparentemente innocue. Spesso non si tratta di un picco di traffico "buono", ma di un attacco DDoS applicativo, cioè uno di quegli attacchi che non puntano a saturare la banda della rete, ma a far esaurire le risorse del server (CPU, memoria, connessioni al database) inviando richieste HTTP che sembrano legittime. In questa guida vediamo come intervenire direttamente sui template Nginx di HestiaCP per aggiungere protezioni contro questo tipo di attacchi e, allo stesso tempo, come sfruttare la cache di Nginx per alleggerire il carico sulle pagine dinamiche (ad esempio generate da PHP), rendendo il sito più resistente anche quando il traffico è legittimo ma molto elevato.
Cos'è un attacco DDoS di "Livello 7" e perché riguarda Nginx
Gli attacchi DDoS (Distributed Denial of Service, "negazione del servizio distribuita") si dividono in diverse categorie in base al livello del modello di rete OSI che colpiscono. Gli attacchi ai livelli 3 e 4 (rete e trasporto) cercano di saturare la larghezza di banda o le tabelle di connessione, e vengono tipicamente filtrati a monte del server, ad esempio dal provider di hosting o da un servizio di protezione come un CDN. Gli attacchi di Livello 7 (il livello "applicazione", quello dove vive il protocollo HTTP) sono più insidiosi perché le singole richieste sono quasi indistinguibili da quelle di un utente reale: una richiesta a una pagina di login, a una ricerca sul sito o a un endpoint che interroga il database, ripetuta migliaia di volte al secondo da molti indirizzi IP diversi, può mettere in ginocchio un server anche con una connessione di rete tutt'altro che satura.
Nginx, essendo il web server che riceve per primo ogni richiesta HTTP in un'installazione HestiaCP (sia quando lavora da solo, sia quando fa da proxy davanti ad Apache), è il punto ideale in cui applicare le prime contromisure: può limitare quante richieste accetta da un singolo indirizzo IP, quante connessioni simultanee mantiene aperte, e può "assorbire" parte del traffico restituendo risposte dalla cache invece di generarle di nuovo ogni volta.
Perché non si modificano i template originali di HestiaCP
In HestiaCP, l'aspetto della configurazione Nginx di ogni dominio non viene scritto a mano: viene generato automaticamente a partire da file modello, chiamati template, che contengono segnaposto come %domain%, %user%, %docroot% o %backend_lsnr%, sostituiti dal sistema con i valori reali del sito quando la configurazione viene creata o ricostruita. I template si trovano in due posizioni sul server, secondo lo scenario:
- Nginx come unico web server (con PHP-FPM):
/usr/local/hestia/data/templates/web/nginx/php-fpm/ - Nginx come reverse proxy davanti ad Apache:
/usr/local/hestia/data/templates/web/nginx/
La documentazione ufficiale di HestiaCP sconsiglia espressamente di modificare i file dei template predefiniti (ad esempio default.tpl): ad ogni aggiornamento del pannello questi file vengono sovrascritti, e le modifiche andrebbero perse. La procedura corretta è copiare i file del template che si vuole personalizzare con un nuovo nome, e modificare solo le copie. Per ogni template servono in genere tre file con la stessa estensione del nome ma estensione diversa, ad esempio hardened.tpl, hardened.stpl (per la versione con certificato SSL) e, se presente, lo script di supporto hardened.sh.
Creare il template personalizzato passo per passo
Collegandosi al server via SSH come root (o con un utente con i permessi adeguati), per creare un template basato su quello predefinito si può procedere così:
cd /usr/local/hestia/data/templates/web/nginx/php-fpm/
cp default.tpl hardened.tpl
cp default.stpl hardened.stpl
A questo punto hardened.tpl e hardened.stpl sono due copie indipendenti, modificabili senza rischiare di perdere le modifiche al prossimo aggiornamento di HestiaCP. Le sezioni seguenti mostrano cosa aggiungere dentro questi file per ottenere le due protezioni principali: limitazione delle richieste e caching.
Limitare le richieste per indirizzo IP: limit_req
La prima e più efficace contromisura contro un attacco applicativo è impedire a un singolo indirizzo IP di inviare un numero eccessivo di richieste in poco tempo. Nginx offre a questo scopo il modulo limit_req, che funziona in due passaggi: prima si definisce una "zona di memoria condivisa" che tiene traccia delle richieste per IP, poi si applica quella zona a una o più sezioni (location) della configurazione.
La definizione della zona va inserita nel blocco http globale di Nginx (file /etc/nginx/nginx.conf, oppure in un file dentro /etc/nginx/conf.d/ incluso automaticamente), non nel template del singolo dominio:
# /etc/nginx/conf.d/ratelimit.conf
limit_req_zone $binary_remote_addr zone=generic:10m rate=30r/m;
limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m;
Qui generic è una zona che consente in media 30 richieste al minuto per ogni IP su tutto il sito, mentre login è una zona più restrittiva (10 richieste al minuto) pensata specificamente per le pagine di autenticazione, tipicamente il bersaglio preferito di questo tipo di attacco. Il valore 10m indica quanta memoria viene riservata per tenere traccia degli indirizzi IP: 10 MB sono sufficienti per circa 160.000 indirizzi distinti, più che adeguati per la maggior parte dei siti.
Fatto questo, dentro il template hardened.tpl si applica la zona generica a tutto il sito e quella più stretta alla pagina di login:
server {
# ... direttive generate automaticamente da HestiaCP ...
limit_req zone=generic burst=15 nodelay;
location = /wp-login.php {
limit_req zone=login burst=5 nodelay;
include /etc/nginx/fastcgi_params;
fastcgi_pass %backend_lsnr%;
}
}
Il parametro burst consente di assorbire brevi raffiche di richieste legittime (ad esempio quando un browser carica più risorse in parallelo) senza bloccare l'utente, mentre nodelay evita che le richieste in eccesso vengano messe in coda, restituendo subito un errore 503 Service Temporarily Unavailable a chi supera il limite. In questo modo, un bot che martella la pagina di login riceve rapidamente errori e smette di consumare risorse del server, mentre un visitatore normale non si accorge di nulla.
Limitare le connessioni simultanee: limit_conn
Un'altra tecnica complementare consiste nel limitare quante connessioni aperte contemporaneamente può avere un singolo IP, utile contro attacchi che aprono molte connessioni e le mantengono occupate il più a lungo possibile. Anche qui la logica è a due passaggi:
# /etc/nginx/conf.d/ratelimit.conf
limit_conn_zone $binary_remote_addr zone=perip:10m;
server {
limit_conn perip 20;
}
Con questa configurazione, un singolo indirizzo IP non potrà avere più di 20 connessioni aperte contemporaneamente verso quel sito: oltre questa soglia, Nginx risponde con un errore senza nemmeno passare la richiesta al backend PHP o ad Apache, risparmiando risorse preziose.
Proteggersi dalle connessioni lente (Slowloris)
Una famiglia di attacchi applicativi, conosciuta come Slowloris, non invia molte richieste, ma apre connessioni e le tiene occupate inviando i dati goccia a goccia, lentissimamente, così da esaurire il numero massimo di connessioni che il server può gestire. La contromisura è impostare timeout stretti per la ricezione degli header e del corpo della richiesta, così che Nginx chiuda le connessioni troppo lente:
server {
client_header_timeout 10s;
client_body_timeout 10s;
send_timeout 10s;
}
I valori predefiniti di Nginx per questi timeout sono 60 secondi, un tempo più che sufficiente a un attacco Slowloris per saturare le connessioni disponibili; abbassarli a 10 secondi (il valore può essere adattato in base alla qualità media delle connessioni dei visitatori reali del sito) riduce drasticamente la finestra di attacco senza impatti percepibili dagli utenti con una connessione normale.
Bloccare IP e User-Agent sospetti
Quando durante un attacco si individuano, analizzando i log, alcuni indirizzi IP ricorrenti o uno User-Agent anomalo usato dal traffico malevolo (molti bot semplici usano uno User-Agent vuoto o palesemente falso), si può aggiungere un blocco diretto nel template:
server {
# Blocca un intervallo di IP
deny 203.0.113.0/24;
# Blocca richieste con User-Agent vuoto o sospetto
if ($http_user_agent ~* "^$|curl|wget|python-requests") {
return 403;
}
}
Questa tecnica va usata con cautela: bloccare per User-Agent è utile solo contro i bot più grezzi, perché quelli più sofisticati imitano perfettamente lo User-Agent di un browser reale, ma resta comunque un filtro a costo quasi nullo che può eliminare una parte del traffico indesiderato prima che arrivi al resto della configurazione.
Ottimizzare il caching dei contenuti dinamici con FastCGI Cache
Le protezioni viste finora riducono il traffico malevolo, ma un secondo pilastro della resilienza è fare in modo che il traffico legittimo (anche quando è molto, ad esempio durante un picco di visite organico) pesi il meno possibile sul server. Per i siti basati su PHP (WordPress compreso) gestiti da HestiaCP con Nginx e PHP-FPM, la soluzione è la FastCGI Cache integrata in Nginx: la prima volta che una pagina viene richiesta, Nginx la genera normalmente passando la richiesta a PHP-FPM, ma ne salva una copia; le richieste successive alla stessa pagina vengono servite direttamente dalla cache, senza più coinvolgere PHP né il database, con un guadagno di velocità enorme e un carico sul server quasi nullo.
Anche in questo caso la zona di cache va definita a livello globale:
# /etc/nginx/conf.d/fastcgi-cache.conf
fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=WPCACHE:100m inactive=60m max_size=1g;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
Poi, dentro il template hardened.tpl, HestiaCP prevede un meccanismo specifico: basta aggiungere, subito dopo l'include fastcgi_params nel blocco che gestisce i file PHP, un riferimento al file di configurazione per-dominio che il pannello genera automaticamente quando la cache viene attivata dall'interfaccia:
location ~ [^/]\.php(/|$) {
fastcgi_pass %backend_lsnr%;
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
include %home%/%user%/conf/web/%domain%/nginx.fastcgi_cache.conf*;
fastcgi_cache WPCACHE;
fastcgi_cache_valid 200 60m;
fastcgi_cache_use_stale updating error timeout invalid_header http_500;
add_header X-FastCGI-Cache $upstream_cache_status;
}
L'header X-FastCGI-Cache è molto utile in fase di verifica: comparirà nella risposta HTTP con il valore HIT quando la pagina viene servita dalla cache, MISS quando viene generata da PHP e salvata per la prima volta, e si può controllare facilmente da browser (strumenti per sviluppatori, scheda Rete) o da terminale con curl -I https://ilsito.it/. L'opzione fastcgi_cache_use_stale con il parametro updating è particolarmente importante durante un picco di traffico: se la cache di una pagina è scaduta nel momento esatto in cui arrivano centinaia di richieste simultanee, Nginx ne invia una sola a PHP per rigenerarla e continua a servire a tutte le altre richieste la versione precedente (leggermente scaduta) finché la nuova non è pronta, evitando che tutte le richieste colpiscano insieme il backend.
Non tutte le pagine devono essere messe in cache: l'area di amministrazione di un CMS o le pagine che mostrano contenuti personalizzati per l'utente collegato vanno escluse, altrimenti un utente potrebbe vedere i dati di un altro. HestiaCP gestisce già in parte questi casi tramite il file nginx.fastcgi_cache.conf generato dal pannello, ma è bene verificare, per CMS specifici come WordPress, che cookie come quelli di sessione o del carrello di un e-commerce disattivino correttamente la cache per quella richiesta tramite una direttiva fastcgi_cache_bypass basata sul valore del cookie.
Applicare il nuovo template e verificare il risultato
Una volta pronti i file hardened.tpl e hardened.stpl, la procedura per attivarli su un dominio è interamente gestita dall'interfaccia di HestiaCP:
- Accedere al pannello, aprire Web > [nome del dominio] > Edit.
- Nel menu a tendina del template Nginx, selezionare il nuovo template
hardened(apparirà automaticamente nell'elenco una volta copiati i file). - Salvare: HestiaCP rigenera la configurazione del dominio a partire dal nuovo template.
In alternativa, da riga di comando, lo stesso risultato si ottiene con:
v-change-web-domain-tpl utente dominio.it hardened
v-rebuild-web-domain utente dominio.it yes
dove l'ultimo parametro yes forza anche il riavvio dei servizi web coinvolti. Prima di applicare la modifica in produzione, è sempre consigliabile verificare la sintassi della configurazione con nginx -t, che segnala eventuali errori senza interrompere il servizio in corso, e testare il comportamento della cache e dei limiti di richiesta su un dominio di prova o in un orario di basso traffico.
Per svuotare la cache FastCGI dopo una modifica al sito (ad esempio un aggiornamento del tema o dei contenuti), HestiaCP offre il pulsante "Purge Nginx Cache" nella pagina di modifica del dominio, oppure il comando v-purge-nginx-cache utente dominio.it da riga di comando.
Conclusioni
Nessuna delle singole misure descritte in questa guida è, da sola, una protezione completa contro un attacco DDoS applicativo serio e prolungato: per quello servono soluzioni dedicate a monte del server, come un CDN con protezione anti-DDoS o un Web Application Firewall. Tuttavia, combinare limitazione delle richieste, limitazione delle connessioni, timeout stretti per i client lenti e una cache FastCGI ben configurata sui template Nginx di HestiaCP alza in modo significativo la soglia di traffico malevolo che il server è in grado di assorbire da solo, e allo stesso tempo migliora le prestazioni del sito anche nei momenti di traffico legittimo elevato. È il tipo di intervento "a basso costo, alto beneficio" che vale la pena fare su qualunque server HestiaCP esposto pubblicamente su Internet.
Fonti ufficiali
Share
What's Your Reaction?
Like
0
Cancella like
0
Amore
0
Buffo
0
arrabbiato
0
Sad
0
Wow
0