Cheatsheet Nginx: comandi, snippet di configurazione e correzione errori

11 min di lettura·Matthieu

Riferimento rapido per le operazioni quotidiane di Nginx su Debian 12 e Ubuntu 24.04. Organizzato per attività per trovare rapidamente ciò che serve. Per una guida completa, vedi Amministrazione di Nginx su un VPS.

Come gestisco il servizio Nginx?

Usa systemctl per controllare Nginx tramite systemd, oppure invia segnali direttamente con nginx -s. Systemctl è lo standard sui sistemi Debian e Ubuntu moderni. I comandi nativi nginx -s comunicano direttamente con il processo master tramite il suo file PID. Entrambi funzionano. Systemctl è migliore per l'automazione e la persistenza all'avvio.

Mappatura segnali e comandi

Azione Comando systemctl Equivalente nginx -s Segnale Unix Effetto sui worker
Avviare sudo systemctl start nginx (non applicabile) - Il master si avvia e genera i worker
Arrestare (graceful) sudo systemctl stop nginx sudo nginx -s quit SIGQUIT I worker completano le richieste in corso, poi si arrestano
Arrestare (immediato) sudo systemctl kill nginx sudo nginx -s stop SIGTERM I worker interrompono le connessioni e si arrestano
Ricaricare la config sudo systemctl reload nginx sudo nginx -s reload SIGHUP Nuovi worker partono con la nuova config. I vecchi completano le richieste, poi si arrestano. Nessuna connessione persa.
Riaprire i log (non integrato) sudo nginx -s reopen SIGUSR1 I worker riaprono i descrittori dei file di log. Da usare dopo la rotazione dei log.
Abilitare all'avvio + avviare ora sudo systemctl enable --now nginx (non applicabile) - Crea il link simbolico per l'avvio, avvia immediatamente
Disabilitare + arrestare sudo systemctl disable --now nginx (non applicabile) - Rimuove il link simbolico dell'avvio, arresta immediatamente

enable --now fa sopravvivere Nginx ai riavvii e lo avvia immediatamente. Preferisci sempre questo comando a un semplice start.

Reload vs restart

reload invia SIGHUP. Il processo master legge la nuova config, genera nuovi worker e lascia che i vecchi completino le connessioni attive. Zero downtime.

restart invia SIGTERM (arresto), poi riavvia da zero. Tutte le connessioni attive vengono interrotte. Usa restart solo per cambiare le porte di ascolto, caricare nuovi moduli o aggiornare il binario Nginx.

Testa sempre prima di ricaricare:

sudo nginx -t && sudo systemctl reload nginx

Se nginx -t fallisce, il ricaricamento non viene eseguito. La config in produzione resta intatta.

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Dopo il ricaricamento:

sudo systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Thu 2026-03-20 10:15:32 UTC; 2s ago

L'enabled nella riga Loaded significa che si avvierà al boot. Installare Nginx su Debian 12 e Ubuntu 24.04 dal repository ufficiale

Come testo e verifico la configurazione Nginx?

Esegui nginx -t per validare la sintassi senza toccare il server in esecuzione. Esegui nginx -T per validare e visualizzare l'intera config analizzata su stdout. Esegui nginx -V per vedere i moduli e i flag di compilazione.

Comando Scopo
sudo nginx -t Testare la sintassi della config, verificare che i file referenziati esistano
sudo nginx -t -q Stesso test, sopprime l'output non-errore (utile negli script)
sudo nginx -T Test + dump della config completa analizzata su stdout
sudo nginx -V Mostra versione, compilatore, argomenti di configure, moduli integrati
sudo nginx -v Mostra solo il numero di versione

Visualizzare e cercare nella config attiva

sudo nginx -T 2>/dev/null | grep -A5 "server_name example.com"

Questo comando mostra la config completa (tutti i file inclusi uniti), poi filtra un blocco server specifico. Più veloce che aprire i file manualmente quando hai decine di include.

Verificare i moduli compilati

sudo nginx -V 2>&1 | tr ' ' '\n' | grep module
--with-http_ssl_module
--with-http_v2_module
--with-http_realip_module
--with-http_gzip_static_module
--with-http_stub_status_module

Non puoi usare una direttiva se il suo modulo non è compilato. È la prima cosa da controllare quando una direttiva causa l'errore "unknown directive".

Dove si trovano i file di configurazione e i log di Nginx?

Su Debian 12 e Ubuntu 24.04, il gestore dei pacchetti installa tutto sotto /etc/nginx/. I log vanno in /var/log/nginx/. Ecco la struttura completa.

Percorso Scopo
/etc/nginx/nginx.conf Config principale. Imposta il numero di worker, events, blocco http, includes
/etc/nginx/sites-available/ File dei blocchi server (disponibili ma non necessariamente attivi)
/etc/nginx/sites-enabled/ Link simbolici a sites-available. Nginx carica questi.
/etc/nginx/conf.d/ Frammenti di config aggiuntivi. Caricati dall'include predefinito in nginx.conf
/etc/nginx/snippets/ Snippet di config riutilizzabili (parametri SSL, header di sicurezza)
/etc/nginx/mime.types Mappatura dei tipi MIME
/var/log/nginx/access.log Log delle richieste
/var/log/nginx/error.log Log degli errori
/run/nginx.pid File PID del processo master

Per abilitare un sito:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Per disabilitare un sito:

sudo rm /etc/nginx/sites-enabled/example.com
sudo nginx -t && sudo systemctl reload nginx

Per un approfondimento sulla struttura delle directory, vedi Struttura dei file di configurazione Nginx.

Quali sono gli snippet di configurazione Nginx più comuni?

Ogni snippet qui sotto è un esempio minimale funzionante. Copia, adatta i valori, testa con nginx -t, ricarica. Per guide complete su ogni argomento, segui i link interni.

Come configuro un blocco server di base?

Un blocco server (virtual host) associa un dominio a una document root. Inserisci questo in /etc/nginx/sites-available/example.com.

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/example.com/html;
    index index.html;

    server_tokens off;

    location / {
        try_files $uri $uri/ =404;
    }
}

server_tokens off nasconde la versione di Nginx dagli header di risposta. Rivelare la versione aiuta gli attaccanti a puntare vulnerabilità note.

Crea il link simbolico in sites-enabled e ricarica. Nginx Server Block: ospita più domini su un VPS

Come reindirizzo HTTP verso HTTPS?

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    return 301 https://$host$request_uri;
}

return 301 è più veloce di rewrite per i redirect di URL completi. Nginx elabora return prima di toccare il filesystem.

Come configuro Nginx come reverse proxy?

Inoltra le richieste a un backend sulla porta 3000. Inserisci questo nel blocco server HTTPS.

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Lo slash finale conta. proxy_pass http://127.0.0.1:3000; (senza slash finale) passa l'URI originale completo. proxy_pass http://127.0.0.1:3000/; (con slash finale) rimuove il prefisso del location. Questa è la causa di molte configurazioni proxy non funzionanti.

Come configurare Nginx come reverse proxy

Come abilito la compressione gzip?

Aggiungi al blocco http {} in /etc/nginx/nginx.conf o a un file snippet:

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_min_length 1024;
gzip_comp_level 5;
gzip_types
    text/plain
    text/css
    text/javascript
    application/json
    application/javascript
    application/xml
    image/svg+xml;

gzip_min_length 1024 salta i file sotto 1 KB. Comprimere file piccoli aggiunge overhead CPU senza una riduzione di dimensione significativa. gzip_comp_level 5 offre un buon equilibrio tra rapporto di compressione e costo CPU. Oltre 6, i benefici diminuiscono.

Ottimizzazione delle prestazioni di Nginx su un VPS

Come aggiungo il rate limiting?

Definisci una zona nel blocco http {}, poi applicala in un blocco location o server.

# In http {} block
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

# In server or location block
location /api/ {
    limit_req zone=api burst=20 nodelay;
    proxy_pass http://127.0.0.1:8080;
}

$binary_remote_addr usa 4 byte per indirizzo IPv4. Una zona da 10 MB contiene circa 160.000 indirizzi. burst=20 consente picchi brevi. nodelay serve le richieste in burst immediatamente anziché metterle in coda.

Rate Limiting con Nginx e protezione DDoS

Come faccio il proxy delle connessioni WebSocket?

location /ws/ {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_read_timeout 86400s;
}

proxy_http_version 1.1 è obbligatorio. HTTP/1.0 non supporta l'header Upgrade. proxy_read_timeout 86400s mantiene le connessioni WebSocket inattive aperte per 24 ore anziché i 60 secondi predefiniti.

Come configuro pagine di errore personalizzate?

server {
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;

    location = /404.html {
        root /var/www/errors;
        internal;
    }

    location = /50x.html {
        root /var/www/errors;
        internal;
    }
}

La direttiva internal impedisce l'accesso diretto alle URL delle pagine di errore. Senza di essa, gli utenti potrebbero navigare direttamente a /404.html.

Come aggiungo header di sicurezza?

Crea /etc/nginx/snippets/security-headers.conf:

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

Includilo in qualsiasi blocco server:

include snippets/security-headers.conf;

Il parametro always aggiunge gli header anche nelle risposte di errore (4xx, 5xx). Senza di esso, Nginx li aggiunge solo sulle 2xx/3xx. Hardening della sicurezza di Nginx su Ubuntu e Debian

Blocco server TLS minimale

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    server_tokens off;

    # ... location blocks
}

Non abilitare TLSv1 o TLSv1.1. Entrambi hanno vulnerabilità note e sono rifiutati dai browser moderni. Configurare Let's Encrypt SSL/TLS per Nginx su Debian 12 e Ubuntu 24.04

Come leggo e faccio il debug dei log Nginx?

Nginx scrive due log per impostazione predefinita: access.log per ogni richiesta e error.log per i problemi. Entrambi si trovano in /var/log/nginx/.

Seguire i log in tempo reale

sudo tail -f /var/log/nginx/error.log

Oppure tramite journald:

journalctl -u nginx -f

Livelli di severità del log degli errori

La direttiva error_log accetta un livello. Dal più al meno dettagliato:

debug > info > notice > warn > error > crit > alert > emerg

Il livello predefinito è error. Per abilitare temporaneamente il log di debug:

error_log /var/log/nginx/error.log debug;

Ricarica Nginx. Il log di debug è estremamente dettagliato. Disabilitalo dopo aver diagnosticato il problema, altrimenti riempirà il disco.

Formato JSON per il log di accesso

I log strutturati sono più facili da analizzare con strumenti come jq, Loki o OpenObserve.

log_format json_combined escape=json
    '{'
        '"time":"$time_iso8601",'
        '"remote_addr":"$remote_addr",'
        '"method":"$request_method",'
        '"uri":"$request_uri",'
        '"status":$status,'
        '"body_bytes_sent":$body_bytes_sent,'
        '"request_time":$request_time,'
        '"upstream_response_time":"$upstream_response_time",'
        '"http_user_agent":"$http_user_agent"'
    '}';

access_log /var/log/nginx/access.log json_combined;

Kit di strumenti per il debug

Comando Cosa fa
curl -I https://example.com Mostra solo gli header di risposta. Controlla codice di stato, versione del server, header di cache.
curl -v https://example.com 2>&1 | head -30 Output dettagliato: handshake TLS, header richiesta/risposta.
sudo nginx -T 2>/dev/null | grep server_name Elenca tutti i server_name configurati in tutti i file di config.
sudo ss -tlnp | grep nginx Mostra su quali porte/indirizzi Nginx è in ascolto.
sudo ls -la /var/log/nginx/ Controlla dimensione e permessi dei file di log.

Abilitare stub_status per il monitoraggio

location /nginx_status {
    stub_status;
    allow 127.0.0.1;
    allow ::1;
    deny all;
}
curl http://127.0.0.1/nginx_status
Active connections: 3
server accepts handled requests
 1542 1542 4890
Reading: 0 Writing: 1 Waiting: 2

Limita stub_status a localhost o all'IP del tuo sistema di monitoraggio. Espone informazioni sul carico del server.

Cosa significano i codici di errore Nginx e come si risolvono?

Quando Nginx restituisce un errore HTTP, il file error.log indica cosa è successo. Ecco i codici più comuni, il loro significato e come risolverli.

Codice Nome Messaggio tipico in error.log Causa comune Soluzione
403 Forbidden directory index of "/var/www/html/" is forbidden File index mancante, permessi file errati, autoindex off (predefinito) Aggiungi un index.html, correggi i permessi (chmod 644 per i file, 755 per le directory), o abilita autoindex on
404 Not Found open() "/var/www/html/page" failed (2: No such file or directory) Percorso root errato, try_files errato, il file non esiste Controlla la direttiva root, verifica il percorso del file su disco
413 Request Entity Too Large client intended to send too large body L'upload supera client_max_body_size (predefinito: 1 MB) Imposta client_max_body_size 50m; nel blocco server o location
502 Bad Gateway connect() failed (111: Connection refused) while connecting to upstream Backend non in esecuzione, porta/socket errata in proxy_pass Avvia il backend, verifica che la porta corrisponda a proxy_pass
503 Service Unavailable no live upstreams while connecting to upstream Tutti i backend in un blocco upstream sono down Avvia almeno un backend, controlla la config degli health check
504 Gateway Timeout upstream timed out (110: Connection timed out) while reading response header Il backend impiega troppo tempo a rispondere Aumenta proxy_read_timeout, ottimizza il backend, controlla i log del backend

Diagnosticare un 502

Il 502 è l'errore proxy più frequente. Procedi passo per passo:

# 1. Is the backend running?
sudo ss -tlnp | grep 3000

# 2. Can Nginx reach it?
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/

# 3. What does the error log say?
sudo tail -20 /var/log/nginx/error.log

Se ss non mostra nulla sulla porta 3000, il backend è fermo. Se curl restituisce una risposta ma Nginx restituisce 502, controlla i permessi dei socket (frequente con i socket Unix di PHP-FPM o Gunicorn).

Quali sono gli errori Nginx più comuni?

Questi causano la maggior parte dei momenti "ho modificato la config e ora è tutto rotto".

Punti e virgola mancanti

Ogni direttiva deve terminare con un punto e virgola. Nginx dà un errore chiaro:

nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/example.com:12

L'errore punta alla riga dopo il punto e virgola mancante, non alla riga del problema. Guarda una riga sopra.

Confusione tra root e alias

# root: appends the location to the path
location /images/ {
    root /var/www;
    # serves /var/www/images/photo.jpg
}

# alias: replaces the location with the path
location /images/ {
    alias /var/www/media/;
    # serves /var/www/media/photo.jpg
}

Con alias, lo slash finale è obbligatorio sia nel location che nel percorso alias. Dimenticarlo causa 404 senza motivo apparente nel log degli errori.

Confusione sull'ordine di valutazione dei location

Nginx valuta i location in quest'ordine, indipendentemente da dove compaiono nel file di config:

  1. = /exact - Corrispondenza esatta. Controllata per prima. Se corrisponde, si ferma immediatamente.
  2. ^~ /prefix - Prefisso preferenziale. La corrispondenza più lunga vince. Se corrisponde, salta tutte le regex.
  3. ~ regex - Regex case-sensitive. Valutata dall'alto verso il basso. La prima corrispondenza vince.
  4. ~* regex - Regex case-insensitive. Stesso ordine dall'alto verso il basso.
  5. /prefix - Prefisso standard. La corrispondenza più lunga vince. Usato solo se nessuna regex ha corrisposto.

Nei prefissi conta la lunghezza della corrispondenza, non l'ordine nel file. Nelle regex conta l'ordine nel file, non la lunghezza. Mescolarli senza capire questo crea routing imprevedibile.

Slash finale in proxy_pass

# No trailing slash: passes /app/foo to backend as /app/foo
location /app/ {
    proxy_pass http://127.0.0.1:3000;
}

# Trailing slash: strips /app/ and passes /foo to backend
location /app/ {
    proxy_pass http://127.0.0.1:3000/;
}

Scegli un approccio e mantieni la coerenza. La maggior parte dei backend si aspetta il percorso completo (nessuno slash finale su proxy_pass).

Dimenticare nginx -t prima del ricaricamento

Se ricarichi con una config errata, Nginx continua a funzionare con la vecchia config e registra un errore. Non va in crash. Ma ora hai una config su disco che non corrisponde alla config in esecuzione. Questo crea confusione in seguito.

Prendi l'abitudine: sudo nginx -t && sudo systemctl reload nginx. Il && assicura che il ricaricamento avvenga solo se il test ha successo.

I file in /etc/nginx/sites-available/ non vengono caricati automaticamente. Devi creare un link simbolico verso /etc/nginx/sites-enabled/. Una copia diretta funziona ugualmente, ma i link simbolici mantengono un'unica fonte di verità.

Qualcosa non funziona?

Sequenza di diagnosi rapida quando Nginx si comporta in modo anomalo:

# Check if Nginx is running
sudo systemctl status nginx

# Test the config
sudo nginx -t

# Check which config is actually loaded
sudo nginx -T 2>/dev/null | head -50

# Check the last 30 error log entries
sudo tail -30 /var/log/nginx/error.log

# Check what ports Nginx is listening on
sudo ss -tlnp | grep nginx

# Check file permissions on the web root
sudo ls -la /var/www/example.com/html/

Se il servizio è in stato di errore, journalctl -u nginx --no-pager -n 50 fornisce la storia completa. Cerca le voci [emerg].

Cheatsheet Nginx: comandi, config e correzione errori