Padroneggiare l'Analisi dei Log di Nginx per una Risoluzione Efficiente dei Problemi

Sblocca una risoluzione efficiente dei problemi padroneggiando i log di accesso e di errore di Nginx. Questa guida spiega come configurare formati di log personalizzati per catturare metriche temporali cruciali, permettendoti di individuare i colli di bottiglia delle prestazioni all'interno di Nginx o del server applicativo a monte. Impara a diagnosticare istantaneamente problemi critici come errori 502 e 504 utilizzando i livelli di gravità del log degli errori e utilizza potenti comandi shell (`grep`, `awk`) per filtrare, contare e analizzare rapidamente i modelli di traffico.

Padroneggiare l'Analisi dei Log di Nginx per una Risoluzione Efficiente dei Problemi

I log di Nginx sono solitamente il modo più veloce per trasformare "il sito è giù" in un problema specifico. Il log di accesso ti dice cosa hanno chiesto i client e quale stato hanno ricevuto. Il log degli errori ti dice cosa Nginx non ha potuto fare: connettersi a un upstream, leggere un certificato, aprire un file, analizzare una configurazione o attendere abbastanza a lungo per una risposta dal backend.

Una buona analisi dei log di Nginx non consiste nel fissare i file finché qualcosa non sembra sospetto. Si tratta di porre una domanda precisa, filtrare rapidamente e correlare il log di accesso con il log degli errori e i log dell'applicazione upstream. Un 502 nel log di accesso è un sintomo. La riga corrispondente nel log degli errori è solitamente l'inizio della risposta.


1. Fondamenti dei Log di Nginx: Accesso vs. Errore

Nginx mantiene due tipi distinti di log, ciascuno con una funzione critica e separata:

1.1 Il Log di Accesso (access.log)

Il Log di Accesso registra i dettagli di ogni richiesta che Nginx elabora. È fondamentale per comprendere il comportamento degli utenti, monitorare il flusso del traffico e valutare i tempi di risposta.

Posizione Predefinita: Tipicamente /var/log/nginx/access.log

Scopo: Tracciare le interazioni del client, le richieste riuscite, gli errori del client, gli errori del server restituiti tramite Nginx, i byte inviati, gli user agent e i tempi di richiesta se configurati.

1.2 Il Log degli Errori (error.log)

Il Log degli Errori tiene traccia dei problemi interni, dei guasti operativi e dei problemi di comunicazione che si verificano durante il ciclo di vita dell'elaborazione di Nginx. Questo log è la fonte definitiva per la risoluzione dei problemi di connettività del backend e degli errori di configurazione del server.

Posizione Predefinita: Tipicamente /var/log/nginx/error.log

Scopo: Tracciare errori lato server, avvisi ed eventi di sistema (errori 5xx, errori di analisi dei file di configurazione).

Livelli di Gravità del Log degli Errori

Nginx utilizza otto livelli di gravità. Quando si risolvono i problemi, in genere si consiglia di iniziare dal livello error o superiore. Il livello di gravità è configurato utilizzando la direttiva error_log:

# Imposta il livello di gravità minimo su 'warn'
error_log /var/log/nginx/error.log warn;
Livello Descrizione Priorità
crit Condizioni critiche, come un grave errore di runtime Più alta
error Si è verificato un errore che ha impedito di soddisfare una richiesta Alta
warn È successo qualcosa di inaspettato, ma le operazioni continuano Media
notice Condizione normale ma significativa (es. riavvio del server) Bassa
info Messaggi informativi Più bassa

Esistono anche i livelli emerg, alert e debug. debug può essere estremamente verboso e di solito richiede una build di Nginx con supporto al debug. Usalo per la risoluzione dei problemi mirata, non come impostazione di produzione normale.

2. Personalizzare i Log di Accesso per l'Analisi delle Prestazioni

Il formato predefinito del log di accesso di Nginx, spesso chiamato combined, è utile ma manca di variabili temporali cruciali per le prestazioni. Per risolvere efficacemente i problemi di lentezza, è necessario definire un formato personalizzato che catturi quanto tempo Nginx ha impiegato per elaborare la richiesta e quanto tempo ha impiegato il server upstream.

2.1 Definire un Formato di Log per le Prestazioni

Utilizza la direttiva log_format (solitamente definita in nginx.conf) per creare un formato personalizzato, ad esempio timing_log:

log_format timing_log '$remote_addr - $remote_user [$time_local] ' 
                    '"$request" $status $body_bytes_sent ' 
                    '"$http_referer" "$http_user_agent" ' 
                    '$request_time $upstream_response_time';

server {
    listen 80;
    server_name example.com;
    
    # Applica il formato personalizzato qui
    access_log /var/log/nginx/timing_access.log timing_log;
    # ... resto della configurazione
}
Variabile Descrizione Valore per la Risoluzione dei Problemi
$request_time Tempo totale trascorso dal primo byte ricevuto all'ultimo byte inviato. Valori alti indicano rete lenta, Nginx lento o backend lento.
$upstream_response_time Tempo trascorso in attesa della risposta del server upstream (es. server applicativo). Valori alti qui individuano l'applicazione backend come il collo di bottiglia.
$status Codice di stato HTTP restituito al client. Essenziale per filtrare gli errori (4xx, 5xx).

Prendi in considerazione l'utilizzo della formattazione JSON dei log quando i log vengono inviati a un sistema centralizzato. Il JSON è più difficile da leggere a occhio, ma molto più facile da analizzare in modo affidabile per gli strumenti. Se mantieni i log in testo semplice, tieni presente che i numeri di campo di awk possono rompersi quando gli user agent, i percorsi delle richieste o i campi tra virgolette contengono spazi.

Considera anche la registrazione degli ID di richiesta. Se il tuo bilanciatore di carico o la tua applicazione invia già un header ID di richiesta, passalo e registralo:

log_format timing_log '$remote_addr [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    'request_time=$request_time '
                    'upstream_time=$upstream_response_time '
                    'request_id=$request_id '
                    'upstream=$upstream_addr';

Un ID di richiesta ti consente di collegare una singola richiesta pubblica lenta a una singola voce di log dell'applicazione. Senza di esso, stai abbinando per timestamp, percorso e IP del client, il che è possibile ma molto meno piacevole.

3. Interpretare le Voci del Log di Accesso

Una voce tipica che utilizza il formato personalizzato potrebbe assomigliare a questa (con i valori temporali aggiunti alla fine):

192.168.1.10 - - [10/May/2024:14:30:05 +0000] "GET /api/data HTTP/1.1" 200 450 "-" "Mozilla/5.0" 0.534 0.528

Diagnosi:

  1. Codice di Stato (200): Successo.
  2. Tempo di Richiesta (0.534s): Il tempo totale è di mezzo secondo.
  3. Tempo Upstream (0.528s): Quasi tutto il tempo è stato speso in attesa dell'applicazione backend (0.534 - 0.528 = 0.006s spesi per overhead di Nginx).

Diagnosi: Per questa richiesta, l'applicazione backend è la probabile fonte della latenza di 500ms. L'overhead di Nginx appare piccolo.

Non generalizzare eccessivamente da una singola riga. Esamina un campione di richieste lente. Se la maggior parte delle richieste lente ha un $upstream_response_time alto, concentrati sull'app o sulla rete upstream. Se $request_time è alto mentre $upstream_response_time è basso, il ritardo potrebbe essere il tempo di upload del client, il download lento del client, il comportamento di buffering o il lavoro lato Nginx.

Risoluzione dei Problemi Utilizzando i Codici di Stato

Intervallo Codice di Stato Significato Azione Tipica/Fonte del Log
4xx (Errori del Client) Il client ha inviato una richiesta non valida o non autorizzata. Controlla i log di accesso per alta frequenza. Cerca 404 Not Found (file mancanti) o 403 Forbidden (problemi di permessi).
5xx (Errori del Server) Nginx o un server upstream non sono riusciti a soddisfare una richiesta valida. Controlla immediatamente il Log degli Errori per le voci corrispondenti.
502 Bad Gateway Nginx non ha potuto ottenere una risposta dall'applicazione upstream. Il log degli errori mostrerà i dettagli (Connessione Rifiutata, Timeout).
504 Gateway Timeout Il server upstream ha impiegato troppo tempo per rispondere entro i limiti proxy configurati. Il log degli errori mostrerà avvisi di timeout. Indaga sulla latenza del backend prima di aumentare i timeout.

Aumentare proxy_read_timeout può nascondere il sintomo mentre gli utenti aspettano ancora troppo. È valido per endpoint a lunga esecuzione, streaming o operazioni note lente, ma per le normali richieste API dovrebbe prima innescare un'indagine sul backend.

4. Diagnosticare Problemi Critici nel Log degli Errori

Quando una richiesta risulta in un errore 5xx, il log di accesso ti dice solo che l'errore si è verificato. Il log degli errori ti dice perché.

Caso di Studio: 502 Bad Gateway

Un errore 502 è uno dei problemi più comuni quando si utilizza Nginx come proxy inverso. Quasi sempre indica che l'applicazione backend è giù, sovraccarica o irraggiungibile.

Cerca questi messaggi specifici nel log degli errori:

4.1 Connessione Rifiutata (Backend Giù)

Ciò indica che Nginx ha tentato di connettersi alla porta del backend ma non c'era nulla in ascolto, il che significa che il server applicativo (es. PHP-FPM, Gunicorn) è fermo o configurato in modo errato.

2024/05/10 14:35:10 [error] 12345#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.1.10, server: example.com, request: "GET /test"
  • Azione: Verifica se il servizio backend è in esecuzione, se è in ascolto sulla porta o sul socket Unix previsto e se Nginx punta allo stesso indirizzo. Riavvia solo dopo aver capito perché si è fermato.

4.2 Connessione Chiusa Prematuramente dall'Upstream (Crash del Backend)

Ciò accade quando Nginx stabilisce una connessione ma il server backend la termina prima di inviare una risposta HTTP completa. Questo spesso suggerisce un errore fatale o un crash nel codice dell'applicazione.

2024/05/10 14:38:22 [error] 12345#0: *2 upstream prematurely closed connection while reading response header from upstream, client: 192.168.1.10, server: example.com, request: "POST /submit"
  • Azione: Controlla i log degli errori nativi del server applicativo (es. log PHP-FPM, log Node.js) per l'errore fatale specifico.

Avvertenza: Se Nginx non riesce a leggere il suo file di configurazione all'avvio, l'errore verrà spesso inviato direttamente all'errore standard o a un file di log di bootstrap, non alla posizione configurata di error.log. Controlla sempre journalctl -xe o i log di sistema se Nginx non si avvia.

Caso di Studio: 403 Forbidden

Un 403 nel log di accesso può essere causato dall'autorizzazione dell'applicazione, dalle regole di accesso di Nginx, dai permessi del filesystem o dal comportamento dell'indice di directory. Il solo log di accesso non può dirti quale.

Cerca nel log degli errori righe come:

2024/05/10 15:02:01 [error] 12345#0: *12 directory index of "/var/www/site/" is forbidden

Ciò significa che Nginx ha raggiunto una directory ma non aveva file indice da servire e l'elenco delle directory è disabilitato. La soluzione potrebbe essere creare l'atteso index.html, regolare la direttiva index o instradare la richiesta all'applicazione.

Per problemi di permessi, potresti vedere:

2024/05/10 15:04:44 [error] 12345#0: *15 open() "/var/www/site/private.txt" failed (13: Permission denied)

Controlla la proprietà del file, i permessi di esecuzione della directory, i criteri SELinux o AppArmor dove applicabile e l'utente con cui vengono eseguiti i worker di Nginx.

Caso di Studio: 499 Richiesta Chiusa dal Client

Lo stato 499 specifico di Nginx significa che il client ha chiuso la connessione prima che Nginx finisse di rispondere. È comune quando gli utenti navigano altrove, i client mobili perdono la connettività o un upstream impiega così tanto tempo che il client si arrende.

Non trattare ogni 499 come un bug di Nginx. Guarda i tempi. Se molti 499 hanno un tempo di richiesta elevato e corrispondono a upstream lenti, gli utenti potrebbero abbandonare le richieste lente. Se si verificano immediatamente da un client o una rete, potrebbe essere un comportamento del client.

5. Comandi Shell Pratici per l'Analisi dei Log

Sebbene i sistemi di monitoraggio dei log robusti siano consigliati per la produzione, la riga di comando di Linux fornisce potenti strumenti per una rapida risoluzione dei problemi in tempo reale.

5.1 Monitoraggio in Tempo Reale

Monitora i log mentre arrivano le richieste (particolarmente utile dopo aver distribuito una correzione o testato una nuova funzionalità):

tail -f /var/log/nginx/access.log
# Oppure, solo per gli errori
tail -f /var/log/nginx/error.log

Per i log ruotati e compressi, usa zgrep:

zgrep '" 50[0-9] ' /var/log/nginx/access.log*.gz

La rotazione dei log è importante durante la revisione degli incidenti. L'errore potrebbe essersi verificato poco prima di mezzanotte o prima che un job di rotazione comprimesse il file di ieri.

5.2 Filtrare e Contare gli Errori

Trova e conta rapidamente gli errori 5xx più frequenti nell'ultima ora o giorno:

# Trova tutte le richieste 5x
grep '" 50[0-9] ' /var/log/nginx/access.log | less

# Conta la distribuzione degli errori 5xx (es. quanti 502 vs. 504)
grep '" 50[0-9] ' /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c | sort -nr

Spiegazione: awk '{print $9}' isola il codice di stato HTTP (supponendo il formato di log predefinito o combinato in cui lo stato è il 9° campo).

Se usi un formato di log personalizzato, conferma il numero del campo prima di fidarti del conteggio. Un controllo rapido più sicuro è stampare alcune righe analizzate:

awk '{print NR, $0; if (NR == 3) exit}' /var/log/nginx/access.log

Per i log JSON, usa jq invece dei numeri di campo:

jq -r 'select(.status >= 500) | .status' /var/log/nginx/access.json \
  | sort | uniq -c | sort -nr

5.3 Identificare le Richieste Lente (Richiede un Formato di Log Personalizzato)

Se hai implementato il formato timing_log (dove $request_time è il penultimo campo, o il campo 16 nel nostro esempio):

# Trova le 10 richieste più lente (es. richieste che richiedono più di 1 secondo)
awk '($16 > 1.0) {print $16, $7}' /var/log/nginx/timing_access.log | sort -nr | head -10

Spiegazione: Questo comando stampa il tempo di richiesta e l'URI ($7) per qualsiasi richiesta che abbia richiesto più di 1.0 secondi, ordinato in modo decrescente.

Un formato di testo semplice più leggibile utilizza valori nominati, come request_time=0.534. Quindi puoi usare grep per intervalli lenti in modo meno elegante ma con meno sorprese sui numeri di campo. Per un'analisi seria, invia i log strutturati a un sistema di log e interroga i percentili per route.

5.4 Identificare i Principali Indirizzi IP Richiedenti

Utile per individuare potenziali tentativi di DoS, picchi di traffico o attività sospette:

# Trova i primi 20 IP che effettuano richieste
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -20

I primi IP sono un punto di partenza, non una prova di abuso. Un NAT aziendale, un edge CDN o un bilanciatore di carico possono far apparire molti utenti come un'unica fonte. Se Nginx è dietro un proxy, configura e registra attentamente l'IP reale del client con real_ip_header e intervalli di proxy attendibili. Non fidarti mai di header X-Forwarded-For arbitrari provenienti da Internet aperto.

Un Flusso Pratico per la Risoluzione dei Problemi

Inizia con il sintomo dell'utente e una finestra temporale. "Il checkout ha restituito 502 intorno alle 14:35 UTC" è molto più utile di "Nginx è rotto".

Per prima cosa, conta gli stati:

grep '10/May/2024:14:3' /var/log/nginx/access.log \
  | awk '{print $9}' | sort | uniq -c | sort -nr

Il filtraggio per data con i log in testo semplice è scomodo e il comando esatto dipende dal formato del log. Per un controllo rapido degli incidenti, anche un filtraggio approssimativo può mostrare se il problema era principalmente 502, 504, 403 o 404.

Successivamente, estrai alcune richieste corrispondenti:

grep '" 502 ' /var/log/nginx/access.log | tail -20

Prendi nota del timestamp, URI, tempo upstream e ID di richiesta se presente. Quindi cerca nel log degli errori intorno allo stesso timestamp:

grep '14:35' /var/log/nginx/error.log

Se l'errore dice connect() failed (111: Connection refused), ispeziona il servizio upstream e la sua porta. Se dice upstream timed out, ispeziona la latenza del backend e l'accodamento. Se dice no live upstreams, ispeziona lo stato di salute dell'upstream, il DNS o la configurazione del bilanciatore di carico.

Infine, controlla i log del backend utilizzando lo stesso ID di richiesta o timestamp. Nginx spesso ti dice dove il passaggio è fallito, ma il log del backend ti dice perché l'applicazione si è comportata in quel modo.

Rendi i Log Utili Prima dell'Interruzione

Il momento peggiore per migliorare la registrazione è durante un'interruzione. Aggiungi i tempi di richiesta, i tempi upstream, l'indirizzo upstream e gli ID di richiesta prima di averne bisogno. Mantieni i log di accesso e di errore separati per sito quando un server ospita più applicazioni. Assicurati che la rotazione mantenga una cronologia sufficiente per gli incidenti che effettivamente analizzi.

Quando qualcosa si rompe, leggi i log in coppia: log di accesso per ciò che è successo, log degli errori per ciò che Nginx non ha potuto fare, log dell'applicazione per ciò che l'upstream ha fatto dopo. Questa abitudine mantiene la risoluzione dei problemi focalizzata e di solito ti porta al vero fallimento più velocemente che modificare i timeout o riavviare i servizi a caso.