Struttura dei file di configurazione Nginx

10 min di lettura·Matthieu|

Una guida completa su come sono organizzati i file di configurazione Nginx su disco, come i contesti si annidano tra loro, come le direttive include importano i file e come funziona l'ereditarietà delle direttive.

Struttura dei file di configurazione Nginx

Hai installato Nginx. Hai aperto /etc/nginx/nginx.conf e hai trovato un file che include altri file, che a loro volta ne includono altri. Alcune direttive si trovano all'interno di parentesi graffe, altre sono al livello superiore. Prima di iniziare a configurare server block, SSL o reverse proxy, ti serve la mappa.

Questo articolo ti fornisce quella mappa. Niente ricette. Solo il modello mentale di come funziona la configurazione di Nginx, per poter leggere e modificare qualsiasi configurazione tu incontri.

Dove sono archiviati i file di configurazione Nginx?

Su Debian 12 e Ubuntu 24.04, il pacchetto apt installa tutto sotto /etc/nginx/. Ecco come appare quella directory su un'installazione appena fatta:

/etc/nginx/
├── nginx.conf              # Main config entry point
├── mime.types              # Maps file extensions to MIME types
├── conf.d/                 # Drop-in config files (*.conf auto-included)
├── sites-available/        # All virtual host config files
│   └── default             # Default server block
├── sites-enabled/          # Symlinks to active virtual hosts
│   └── default -> ../sites-available/default
├── snippets/               # Reusable config fragments
│   └── fastcgi-php.conf
├── modules-available/      # Available dynamic module configs
├── modules-enabled/        # Symlinks to loaded modules
├── fastcgi.conf            # FastCGI directive defaults
├── fastcgi_params          # FastCGI parameter mappings
├── proxy_params            # Proxy header defaults
├── scgi_params             # SCGI parameter mappings
├── uwsgi_params            # uWSGI parameter mappings
├── koi-utf                 # Character set mapping files
├── koi-win
└── win-utf

Puoi verificarlo sul tuo server:

ls -la /etc/nginx/

Il file che modifichi più spesso non è nginx.conf stesso. Di solito è un file dentro sites-available/ o conf.d/. Il file principale nginx.conf imposta i valori predefiniti globali e importa quei file tramite direttive include.

Come sono organizzati i file di configurazione Nginx?

La configurazione di Nginx usa un albero di contesti (contexts) annidati. Ogni contesto è una direttiva di blocco racchiusa tra parentesi graffe. Le direttive inserite in un contesto si applicano solo all'interno di quel campo d'azione.

La gerarchia è questa:

main (top level, outside any braces)
├── events { }
└── http { }
    └── server { }
        └── location { }

Ogni direttiva nella configurazione si trova a uno di questi livelli. Il contesto main è il file stesso. Tutto il resto si annida al suo interno.

Cosa controlla il contesto main?

Il contesto main è tutto ciò che si trova al di fuori di qualsiasi direttiva di blocco in nginx.conf. Controlla le impostazioni a livello di processo che riguardano l'intera istanza Nginx.

Direttive principali a questo livello:

Direttiva Scopo Valore tipico
user Utente OS con cui girano i processi worker www-data
worker_processes Numero di processi worker auto (corrisponde ai core della CPU)
pid Percorso del file PID /run/nginx.pid
error_log Percorso e livello del log errori globale /var/log/nginx/error.log
include Carica le configurazioni dei moduli /etc/nginx/modules-enabled/*.conf

Ecco il contesto main dal file nginx.conf predefinito di Debian 12:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;

Queste cinque righe vengono eseguite prima di tutto il resto. Stabiliscono con quale utente gira Nginx, quanti worker avvia e dove scrive gli errori.

Cosa va nel blocco events?

Il blocco events configura come Nginx gestisce le connessioni a livello di sistema operativo. Si trova all'interno del contesto main.

events {
    worker_connections 768;
    # multi_accept on;
}

worker_connections imposta il numero massimo di connessioni simultanee per ogni processo worker. Con worker_processes auto su una macchina a 4 core, si ottengono 4 x 768 = 3.072 connessioni concorrenti. Il valore predefinito nel sorgente Nginx è 512, ma Debian lo imposta a 768.

A cosa serve il contesto http?

Il blocco http contiene tutta la configurazione relativa alla gestione del traffico HTTP. Ogni blocco server si trova al suo interno. Le direttive inserite qui si applicano a tutti i virtual host, a meno che un blocco server o location non le sovrascriva.

http {
    sendfile on;
    tcp_nopush on;
    types_hash_max_size 2048;
    server_tokens off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

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

    gzip on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Nota server_tokens off; vicino all'inizio. Questa direttiva nasconde il numero di versione di Nginx dagli header delle risposte. La divulgazione della versione aiuta gli attaccanti a prendere di mira vulnerabilità note. L'impostazione predefinita di Debian non include questa riga. Aggiungila.

Le due righe include in fondo sono il modo in cui Nginx importa le configurazioni effettive dei tuoi siti. Vedremo include in dettaglio più avanti.

Come funzionano i server block?

Un blocco server definisce un virtual host. Si trova all'interno del contesto http. Ogni blocco server è in ascolto su una combinazione indirizzo/porta e abbina le richieste tramite l'header Host.

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

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

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

Quando arriva una richiesta, Nginx seleziona il blocco server confrontando server_name con l'header Host. Se nessun blocco corrisponde, Nginx usa il default_server:

listen 80 default_server;

Di solito si crea un file per dominio in sites-available/, ognuno contenente un blocco server (o due, se hai sia HTTP che HTTPS).

Come abbina Nginx i blocchi location?

Un blocco location definisce come Nginx gestisce le richieste per pattern URI specifici. Si trova all'interno di un blocco server (o all'interno di un altro location).

Nginx valuta i blocchi location in un ordine preciso:

Modificatore Tipo Esempio Comportamento
= Corrispondenza esatta location = / Corrisponde solo a /. Interrompe la ricerca immediatamente.
^~ Prefisso con priorità location ^~ /images/ Corrisponde al prefisso. Salta i controlli regex.
~ Regex (case-sensitive) location ~ \.php$ Vince la prima corrispondenza regex.
~* Regex (case-insensitive) location ~* \.(jpg|png)$ Vince la prima corrispondenza regex.
(nessuno) Prefisso location /api/ Vince il prefisso più lungo, ma una regex può sovrascriverlo.

L'algoritmo di corrispondenza:

  1. Nginx controlla tutte le location con prefisso e memorizza la corrispondenza più lunga.
  2. Se quella corrispondenza usa = o ^~, si ferma e la usa.
  3. Altrimenti, controlla le location regex nell'ordine in cui appaiono nel file di configurazione.
  4. Vince la prima corrispondenza regex. Se nessuna regex corrisponde, usa il prefisso più lungo dal passo 1.

Questo significa che l'ordine delle location con prefisso nel file di configurazione non conta. Ma l'ordine delle regex sì.

Come funziona la direttiva include?

La direttiva include inserisce il contenuto di un altro file (o di file che corrispondono a un pattern glob) nella posizione corrente della configurazione. Nginx la risolve al momento del caricamento della configurazione, prima che venga analizzata nel suo insieme.

include /etc/nginx/mime.types;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

Il glob *.conf corrisponde a tutti i file che terminano con .conf in quella directory. Il glob * corrisponde a tutto. Entrambi sono pattern comuni.

La direttiva include funziona in qualsiasi contesto. Puoi usarla all'interno dei blocchi http, server o location:

server {
    listen 443 ssl;
    include snippets/ssl-params.conf;
}

Ecco come funziona snippets/. Scrivi un frammento riutilizzabile una volta e lo includi ovunque ti serva.

Un aspetto da tenere d'occhio: Nginx non riesce ad avviarsi se un glob include non corrisponde a nessun file e il percorso non è un glob. Se scrivi include /etc/nginx/conf.d/*.conf; e la directory è vuota, Nginx si avvia senza problemi (i glob possono non corrispondere a nulla). Ma include /etc/nginx/ssl.conf; fallirà se quel file non esiste.

Qual è la differenza tra sites-available, sites-enabled e conf.d?

Queste tre directory hanno scopi diversi. Debian e Ubuntu le usano tutte e tre.

Directory Scopo Come la legge Nginx Quando usarla
sites-available/ Contiene tutte le configurazioni dei virtual host Non viene letta direttamente Sempre. Un file per dominio.
sites-enabled/ Contiene symlink alle configurazioni attive Inclusa tramite include /etc/nginx/sites-enabled/*; Crea un symlink qui per attivare un sito.
conf.d/ Frammenti di configurazione drop-in Inclusa tramite include /etc/nginx/conf.d/*.conf; Impostazioni http globali, blocchi upstream, mappe.

Il pattern sites-available / sites-enabled permette di disabilitare un sito senza cancellare la sua configurazione. Per abilitare un sito:

ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

Per disabilitarlo:

rm /etc/nginx/sites-enabled/example.com

Poi ricarica:

sudo nginx -t && sudo systemctl reload nginx

Esegui sempre nginx -t prima di ricaricare. Valida la configurazione senza influire sul traffico in corso.

La directory conf.d/ è più semplice. Ogni file .conf al suo interno viene caricato automaticamente. Non servono symlink. Alcuni amministratori preferiscono conf.d/ per la sua semplicità e ignorano del tutto sites-available/sites-enabled. Entrambi gli approcci funzionano. Scegline uno e mantieni la coerenza.

Un'insidia: se usi sia conf.d/ che sites-enabled/, assicurati di non definire blocchi server in conflitto in entrambe le posizioni. Nginx li caricherà entrambi, e il risultato dipende dalle regole di fusione delle direttive e dalla corrispondenza di server_name.

Come funziona l'ereditarietà delle direttive Nginx?

Nginx passa le direttive dai contesti padre ai contesti figli. Questa è la parte che la maggior parte delle persone sbaglia, e la fonte di bug sottili in produzione.

Esistono tre tipi di direttive, e ognuno eredita in modo diverso.

Direttive normali

Le direttive normali contengono un singolo valore. Se un contesto figlio definisce la stessa direttiva, sostituisce completamente il valore del padre. Se il figlio non la definisce, il valore del padre viene ereditato.

Esempio: root è una direttiva normale.

http {
    root /var/www/default;

    server {
        server_name example.com;
        # root is inherited: /var/www/default

        location /app {
            root /var/www/app;
            # root is overridden: /var/www/app
        }

        location /blog {
            # root is inherited: /var/www/default
        }
    }
}

Altre direttive normali: index, access_log (se usata una sola volta), error_log, client_max_body_size.

Direttive array

Le direttive array possono apparire più volte nello stesso contesto per accumulare valori. Ma quando un contesto figlio ne definisce anche solo un'istanza, sostituisce tutti i valori del padre. Non li unisce. Li sostituisce.

add_header è la direttiva array più comune. Questo comportamento causa un bug di produzione ben noto.

Cosa succede quando si aggiungono header sia nel blocco http che in quello location?

Se definisci add_header nel contesto http e poi definisci un add_header diverso in un blocco location, il blocco location cancella tutti gli header dal contesto http. Non solo quello che stai sovrascrivendo. Tutti.

http {
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    server {
        server_name example.com;

        location /api/ {
            add_header X-Custom "api-response";
            # X-Frame-Options is GONE
            # X-Content-Type-Options is GONE
            # Only X-Custom is sent
        }
    }
}

Per verificare che questo stia accadendo sul tuo server:

curl -I https://example.com/api/

Controlla gli header di risposta. Se i tuoi header di sicurezza mancano dalle risposte di /api/ ma sono presenti sugli altri percorsi, ecco il motivo.

La soluzione: ripeti tutti gli header nel contesto figlio.

location /api/ {
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";
    add_header X-Custom "api-response";
}

Oppure usa uno snippet:

# /etc/nginx/snippets/security-headers.conf
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Strict-Transport-Security "max-age=63072000" always;
location /api/ {
    include snippets/security-headers.conf;
    add_header X-Custom "api-response";
}

Nota: Nginx 1.29.3+ ha introdotto add_header_inherit merge; che modifica questo comportamento. Con merge, i contesti figli aggiungono agli header del padre invece di sostituirli. Se stai usando Nginx 1.28.x (l'attuale versione stabile a marzo 2026), non hai ancora questa funzionalità.

Lo stesso comportamento di sostituzione totale si applica a proxy_set_header. Se definisci qualsiasi proxy_set_header in un blocco location, tutte le direttive proxy_set_header dal contesto server o http vengono perse. La documentazione ufficiale lo afferma esplicitamente: "These directives are inherited from the previous configuration level if and only if there are no proxy_set_header directives defined on the current level."

server {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location /api/ {
        proxy_set_header X-Request-ID $request_id;
        # Host, X-Real-IP, X-Forwarded-For are all GONE
        proxy_pass http://backend;
    }
}

Risolvilo allo stesso modo: ripeti tutti gli header nel blocco location, oppure usa uno snippet con include.

Direttive azione

Le direttive azione come rewrite e return non ereditano nei contesti annidati. Vengono eseguite solo nel contesto in cui sono definite.

server {
    rewrite ^/old/(.*)$ /new/$1 permanent;

    location /app {
        # The rewrite above does NOT apply here
        # Requests matching /app are handled by this location
    }
}

La direttiva try_files ha una particolarità correlata. Quando viene inserita nel contesto server, Nginx crea una pseudo-location implicita con la priorità più bassa possibile. Se un qualsiasi blocco location regolare corrisponde alla richiesta, try_files a livello di server non viene mai eseguita:

server {
    try_files $uri /index.php;   # Never runs for /app/* requests
    location /app { }            # This catches them first
}

Inserisci sempre try_files all'interno di un blocco location specifico.

Come si ispeziona la configurazione Nginx effettiva?

Due comandi ti aiutano a capire cosa vede realmente Nginx dopo aver risolto tutte le direttive include.

Testa la configurazione per errori di sintassi:

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

Esegui sempre questo comando prima di ricaricare. Se il test fallisce, Nginx ti indica il file e il numero di riga.

Scarica l'intera configurazione unificata:

sudo nginx -T

Questo produce in output l'intera configurazione effettiva con tutti gli include risolti ed espansi inline. Passa l'output a less per una migliore leggibilità:

sudo nginx -T | less

Oppure cerca una direttiva specifica:

sudo nginx -T | grep -n "add_header"

Questo mostra ogni direttiva add_header in tutti i file inclusi, con i numeri di riga nell'output unificato. Usalo quando fai debug di problemi di ereditarietà. Se un header appare nel blocco http ma non in un blocco location, e non vedi nessun add_header in quella location, l'header viene ereditato. Se vedi un add_header diverso nella location, tutti gli header del padre vengono cancellati.

Usa nginx -T ogni volta che le modifiche alla configurazione non si comportano come previsto.

Riferimento rapido: il quadro completo

/etc/nginx/nginx.conf
│
├─ main context (process-level: user, worker_processes, pid)
│
├─ events { }  (connection handling: worker_connections)
│
└─ http { }    (all HTTP config)
   │
   ├─ include conf.d/*.conf      (global HTTP settings, upstreams, maps)
   ├─ include sites-enabled/*    (virtual host configs)
   │
   └─ server { }                 (one per domain/port)
      │
      ├─ listen, server_name     (routing)
      ├─ root, index             (defaults for this host)
      │
      └─ location { }           (URI pattern matching)
         ├─ try_files, root      (per-path behavior)
         └─ proxy_pass           (reverse proxy target)

Inheritance: parent -> child (down only)
Normal directives: child overrides parent
Array directives: child REPLACES ALL parent values
Action directives: no inheritance

Copyright 2026 Virtua.Cloud. Tutti i diritti riservati. Questo contenuto è un'opera originale del team Virtua.Cloud. La riproduzione, ripubblicazione o redistribuzione senza autorizzazione scritta è vietata.

Pronto a provare?

Distribuisci il tuo server in pochi secondi. Linux, Windows o FreeBSD.

Vedi piani VPS