Hai un Nginx che funziona, ma senti che il server potrebbe spingere di più. Le pagine caricano in 2 secondi invece di 800ms, il carico CPU sale senza motivo, e le connessioni concorrenti sembrano strozzarsi. Il problema, quasi sempre, non è la macchina: è la configurazione di default. Noi, di Meteora Web, lo vediamo ogni volta che prendiamo in mano un server nuovo: worker process, keepalive e cache sono le tre leve che separano un server pigro da un server che vola. E non serve essere sysadmin da dieci anni per ottimizzarle — serve capire cosa fa ogni direttiva e dove mettere le mani. In questa guida ti portiamo direttamente al sodo: tre aree di intervento, codici pronti da copiare, e la logica per non rompere nulla.
Quanto incidono worker process e worker connections sulle performance?
È la prima domanda che ci fanno i clienti quando guardiamo il loro nginx.conf: «Ma metto worker_processes 8 o 4?». La risposta è più sottile di quanto sembri. Nginx non è Apache: non crea un processo per connessione. Usa un modello event-driven asincrono. Questo significa che un singolo worker può gestire migliaia di connessioni simultanee — se configurato bene.
Il numero di worker corretto
La regola classica: un worker per core CPU. Su server moderni con hyper-threading, il valore auto è la scelta migliore perché Nginx rileva il numero di core disponibili. Non forzarlo mai a un numero superiore ai core fisici: aumenti solo il context switching senza guadagno. Ecco la configurazione base:
Sponsored Protocol
worker_processes auto;
worker_rlimit_nofile 65535;
worker_rlimit_nofile alza il limite di file descriptor per ogni worker — fondamentale se gestisci molte connessioni. Di default il sistema operativo ha limiti bassi (1024). Senza questo, anche con worker allo stato bagnato, il server rifiuta connessioni.
worker_connections: quanto può reggere un worker?
La direttiva worker_connections definisce il massimo numero di connessioni che un singolo worker può aprire contemporaneamente. Il valore totale massimo è worker_processes × worker_connections. Per un server medio (4 core, 8GB RAM) con traffico normale, 4096 è un ottimo punto di partenza:
events {
worker_connections 4096;
multi_accept on;
use epoll;
}
- multi_accept on: fa accettare più connessioni in un colpo solo dal worker. Su Linux con epoll è d’obbligo per non perdere pacchetti.
- use epoll: forza Nginx a usare il metodo di multiplexing più efficiente su Linux. Di default lo rileva automaticamente, ma esplicitarlo non fa male.
Errore comune: impostare worker_connections a 65535 e poi non alzare worker_rlimit_nofile. Il sistema blocca il worker prima ancora che Nginx provi a gestire quel numero di connessioni. Controlla sempre i limiti di sistema con ulimit -n e, se serve, modificali in /etc/security/limits.conf.
Sponsored Protocol
Come configurare keepalive per ridurre overhead di connessione?
Ogni connessione TCP costa: handshake, negoziazione TLS (se HTTPS), chiusura. Se il browser apre una connessione per ogni singola risorsa (CSS, JS, immagini), i client si accumulano e il server si intasa. Keepalive riutilizza la stessa connessione per più richieste, riducendo la latenza e il carico. La differenza? Un server senza keepalive può gestire 100 utenti con 1000 richieste; con keepalive ben configurato, gli stessi 100 utenti generano 100 richieste — il resto sono riutilizzi.
Proxy verso backend (PHP, Node, etc.)
La maggior parte del traffico passa da Nginx a un backend (PHP-FPM, Gunicorn, Node). Qui keepalive è doppiamente cruciale: evita di aprire una nuova connessione TCP per ogni richiesta verso il backend. Configurazione base per upstream:
upstream php_backend {
server 127.0.0.1:9000;
keepalive 32;
}
server {
location ~ \.php$ {
fastcgi_pass php_backend;
fastcgi_keep_conn on;
include fastcgi_params;
}
}
keepalive 32 dice a Nginx di mantenere aperte fino a 32 connessioni verso il backend, da riutilizzare. fastcgi_keep_conn on abilita il keepalive per il backend FastCGI. Senza quest’ultima, le connessioni vengono chiuse dopo ogni richiesta — e le direttive upstream keepalive diventano inutili.
Sponsored Protocol
Keepalive lato client (visitatore)
Per i client finali, Nginx di default tiene la connessione aperta per 75 secondi (keepalive_timeout 75). Questo va bene per siti statici, ma su applicazioni dinamiche con login e AJAX può essere ridotto a 30 secondi per liberare risorse più velocemente. Ecco un bilanciamento tipico:
keepalive_timeout 30;
keepalive_requests 100;
keepalive_requests 100 limita il numero di richieste su una singola connessione keepalive. Dopo 100 richieste, la connessione viene chiusa e una nuova viene creata. Utile per evitare che una connessione rimanga aperta troppo a lungo su un client difettoso.
Quali direttive di caching usare per ridurre carico e velocizzare risposte?
Il caching in Nginx è un silos di performance: se ben configurato, le pagine statiche o le risposte API vengono servite dalla cache senza toccare il backend. Noi, di Meteora Web, abbiamo ridotto il carico CPU del 70% su un e-commerce con traffico stagionale solo abilitando proxy_cache per le pagine prodotto non personalizzate. Il trucco è sapere cosa mettere in cache e per quanto.
Proxy cache per reverse proxy (pagine dinamiche)
Se Nginx agisce da proxy per un’applicazione (WordPress, Laravel, API), puoi memorizzare le risposte in una cache su disco. Configurazione base:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mycache:10m max_size=1g inactive=60m use_temp_path=off;
server {
location / {
proxy_cache mycache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 302 60m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_pass http://backend;
}
}
- proxy_cache_path: definisce dove salvare la cache.
levels=1:2organizza i file in sottodirectory per evitare troppi file nella stessa cartella.max_size=1glimita la cache a 1GB.inactive=60mrimuove i file non acceduti per 60 minuti. - proxy_cache_valid: per quanto tempo tenere in cache le risposte con codice 200/302 (60 minuti) e 404 (1 minuto).
- proxy_cache_use_stale: se il backend crasha, Nginx serve la versione scaduta della cache — meglio di un errore 502.
FastCGI cache per PHP
Per WordPress, Laravel e altri CMS PHP, fastcgi_cache è ancora più diretto: cache delle pagine renderizzate da PHP-FPM. Configurazione tipica:
Sponsored Protocol
fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=phpcache:10m max_size=2g inactive=60m use_temp_path=off;
server {
location ~ \.php$ {
fastcgi_cache phpcache;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_valid 200 60m;
fastcgi_pass php_backend;
}
}
Attenzione: non cachetare pagine con cookie di sessione o contenuti personalizzati. Puoi escluderle con fastcgi_cache_bypass $http_cookie se il cookie contiene un token di autenticazione. Altrimenti rischi di servire a un utente loggato la pagina di un altro.
Sponsored Protocol
Cosa fare adesso
Hai tre leve da tirare subito:
- Controlla la configurazione attuale: sul tuo server esegui
nginx -tper verificare errori, poinginx -T | grep -E 'worker_processes|worker_connections|keepalive|proxy_cache'per vedere cosa hai ora. - Applica le modifiche graduali: una direttiva alla volta. Ricarica Nginx con
nginx -s reloade testa conab -n 1000 -c 100 https://tuosito.com/(Apache Benchmark) o conwrkper misurare richieste al secondo e latenza. - Monitora con amp;gtop o netdata: guarda l’uso CPU, memoria, numero di connessioni attive (
nginx -s reopenlog?). Se vedi picchi diworker_connectionsesaurite (errori 503 nel log), aumenta il valore e controlla ulimit. - Non dimenticare la sicurezza: una cache va ripulita periodicamente e protetta da accessi non autorizzati. Usa
proxy_cache_purgese hai bisogno di invalidare cache su richiesta.
Per approfondire tutti i fondamenti di Nginx in produzione, leggi la nostra guida pillar su Nginx e Web Server Configuration. Lì tocchiamo anche virtual host, SSL, log e molto altro — quello che ti serve per non avere più scuse.