Host Virtuali Nginx: Ospitare Più Siti Web su un Singolo Server

Sfrutta la potenza degli host virtuali (server block) di Nginx per ospitare efficientemente più siti web o sottodomini su un singolo server. Questa guida fornisce un tutorial completo e passo-passo, coprendo la configurazione delle directory, la creazione dei file di configurazione, l'attivazione dei server block e il test di Nginx. Impara le migliori pratiche per sottodomini, server block predefiniti, integrazione HTTPS e logging dedicato. Esempi pratici e suggerimenti essenziali per la risoluzione dei problemi ti aiuteranno a padroneggiare l'hosting multi-sito con Nginx, ottimizzando l'uso delle risorse e semplificando la gestione del server web.

Host Virtuali Nginx: Ospitare Più Siti Web su un Singolo Server

Gestire diversi siti di piccole dimensioni da un unico server è un compito normale per Nginx. Potresti avere un sito aziendale, un sito di documentazione, un'app di staging e un portale clienti, tutti sulla stessa macchina. Nginx li separa tramite blocchi server. Gli utenti di Apache chiamano spesso questa stessa idea "host virtuali", quindi vedrai entrambi i termini usati in tutorial e pannelli di hosting.

La parte importante è semplice: Nginx guarda la porta, l'indirizzo IP e l'header Host, quindi sceglie il blocco server corrispondente. Se viene caricato il sito sbagliato, il problema di solito non è misterioso. Spesso è un record DNS mancante, un errore di battitura in server_name, un server predefinito che intercetta la richiesta o due file con lo stesso nome.

Comprendere i Server Block (Host Virtuali) di Nginx

Al suo interno, un server block di Nginx è una direttiva di configurazione definita all'interno del file di configurazione di Nginx (nginx.conf o file inclusi). Ogni blocco server definisce la configurazione per uno specifico host virtuale, dettando come Nginx deve rispondere alle richieste per un particolare dominio o insieme di domini. Nginx usa la direttiva listen per specificare l'indirizzo IP e la porta su cui ascoltare, e la direttiva server_name per identificare a quali nomi di dominio o hostname questo blocco server deve rispondere.

Quando arriva una richiesta, Nginx esamina l'header Host della richiesta HTTP e lo confronta con le direttive server_name dei suoi blocchi server configurati. Quindi serve il contenuto definito nel blocco server corrispondente. Se nessun server_name corrisponde, Nginx di solito ricade sul server block predefinito (il primo blocco server o uno esplicitamente contrassegnato come default_server).

Prerequisiti

Prima di iniziare, assicurati di avere quanto segue:

  1. Nginx Installato: Nginx deve essere installato e in esecuzione sul tuo server. In caso contrario, di solito puoi installarlo tramite il gestore pacchetti del tuo sistema (es., sudo apt update && sudo apt install nginx su Ubuntu/Debian, sudo yum install nginx su CentOS/RHEL).
  2. Nomi di Dominio: Hai bisogno di almeno due nomi di dominio (es., example1.com e example2.com) o sottodomini (es., blog.example.com e app.example.com) che vuoi ospitare. I record DNS A/AAAA di questi domini devono puntare all'indirizzo IP pubblico del tuo server.
  3. Struttura di Directory di Base: Un piano per dove risiederanno i file del tuo sito web. Una pratica comune è /var/www/tuodominio.com/html.
  4. Privilegi Sudo: Avrai bisogno dell'accesso sudo per modificare i file di configurazione di Nginx.

Guida alla Configurazione Passo-Passo

Configuriamo due host virtuali: example1.com e example2.com.

Passo 1: Creare la Struttura delle Directory per i Siti Web

Per prima cosa, crea le directory root per ciascuno dei tuoi siti web. Qui verranno memorizzati i loro file HTML, CSS, JavaScript e altri file statici. Una posizione comune è /var/www/.

sudo mkdir -p /var/www/example1.com/html
sudo mkdir -p /var/www/example2.com/html

# Imposta la proprietà al tuo utente (sostituisci $USER con il tuo nome utente) per consentire la modifica
sudo chown -R $USER:$USER /var/www/example1.com/html
sudo chown -R $USER:$USER /var/www/example2.com/html

# Imposta i permessi di lettura per il server web
sudo chmod -R 755 /var/www

Successivamente, crea un semplice file index.html in ciascuna directory per testare la configurazione:

Per /var/www/example1.com/html/index.html:

<!-- /var/www/example1.com/html/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Benvenuto su Example1.com!</title>
</head>
<body>
    <h1>Successo! Questo è Example1.com.</h1>
    <p>Questo host virtuale funziona correttamente.</p>
</body>
</html>

Per /var/www/example2.com/html/index.html:

<!-- /var/www/example2.com/html/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Benvenuto su Example2.com!</title>
</head>
<body>
    <h1>Successo! Questo è Example2.com.</h1>
    <p>Anche questo host virtuale funziona!</p>
</body>
</html>

Passo 2: Creare i File di Configurazione dei Server Block di Nginx

Nginx carica tipicamente le configurazioni dei server block dai file nella directory /etc/nginx/sites-enabled/. Questi file sono solitamente collegamenti simbolici alle configurazioni memorizzate in /etc/nginx/sites-available/. Questa separazione ti permette di memorizzare configurazioni non ancora attive o di abilitare/disabilitare facilmente i siti.

Crea un nuovo file di configurazione per example1.com:

sudo nano /etc/nginx/sites-available/example1.com.conf

Aggiungi il seguente contenuto:

# /etc/nginx/sites-available/example1.com.conf
server {
    listen 80;
    listen [::]:80;

    root /var/www/example1.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name example1.com www.example1.com;

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

    access_log /var/log/nginx/example1.com_access.log;
    error_log /var/log/nginx/example1.com_error.log;
}

Spiegazione delle Direttive:

  • listen 80;: Nginx ascolta sulla porta 80 (HTTP standard). listen [::]:80; è per IPv6.
  • root /var/www/example1.com/html;: Specifica la root dei documenti per questo server block. Nginx cercherà i file all'interno di questa directory.
  • index index.html ...;: Definisce il file predefinito che Nginx deve servire quando viene richiesta una directory (es., quando qualcuno visita example1.com/).
  • server_name example1.com www.example1.com;: Questo è cruciale. Dice a Nginx di rispondere alle richieste per example1.com o www.example1.com usando la configurazione di questo server block.
  • location / { ... }: Un blocco che definisce come gestire le richieste per URI specifici. try_files tenta di servire un file direttamente ($uri), poi una directory ($uri/), e infine restituisce un errore 404 Not Found.
  • access_log e error_log: Specifica file di log separati per questo sito specifico, una buona pratica per un debugging e un'analisi più facili.

Ora, crea un file di configurazione simile per example2.com:

sudo nano /etc/nginx/sites-available/example2.com.conf

Aggiungi il seguente contenuto:

# /etc/nginx/sites-available/example2.com.conf
server {
    listen 80;
    listen [::]:80;

    root /var/www/example2.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name example2.com www.example2.com;

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

    access_log /var/log/nginx/example2.com_access.log;
    error_log /var/log/nginx/example2.com_error.log;
}

Passo 3: Abilitare i Server Block

Per abilitare queste configurazioni, crea collegamenti simbolici dalla directory sites-available alla directory sites-enabled. Questo dice a Nginx di includere questi file all'avvio.

sudo ln -s /etc/nginx/sites-available/example1.com.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/example2.com.conf /etc/nginx/sites-enabled/

Passo 4: Testare la Configurazione di Nginx

È fondamentale testare la configurazione di Nginx per errori di sintassi prima di ricaricarla. Questo impedisce a Nginx di non riavviarsi a causa di un errore di battitura.

sudo nginx -t

Dovresti vedere un output simile a questo, che indica il successo:

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

Se vedi errori, correggili nei rispettivi file di configurazione e riesegui sudo nginx -t finché non passa.

Passo 5: Riavviare Nginx

Applica la nuova configurazione riavviando o ricaricando Nginx. reload è generalmente preferito perché permette a Nginx di caricare nuove configurazioni senza interrompere le connessioni attive.

sudo systemctl reload nginx
# Oppure, se reload non funziona o per installazioni nuove:
sudo systemctl restart nginx

Passo 6: Aggiornare i Record DNS

Assicurati che i record DNS A per example1.com, www.example1.com, example2.com e www.example2.com puntino tutti all'indirizzo IP del tuo server Nginx. Senza voci DNS corrette, il tuo browser non saprà dove trovare i tuoi siti web.

Una volta completata la propagazione DNS (che può richiedere da pochi minuti a diverse ore), dovresti essere in grado di visitare http://example1.com e http://example2.com nel tuo browser web e vedere le rispettive pagine index.html.

Scenari Avanzati e Migliori Pratiche

Ospitare Sottodomini

Ospitare sottodomini (es., blog.example.com, shop.example.com) funziona esattamente come ospitare domini separati. Devi solo definire un nuovo server block con il sottodominio come server_name.

Esempio per blog.example.com:

# /etc/nginx/sites-available/blog.example.com.conf
server {
    listen 80;
    listen [::]:80;

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

    server_name blog.example.com;

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

Ricorda di creare la directory (/var/www/blog.example.com/html), creare un index.html, creare il collegamento simbolico e ricaricare Nginx.

Il Server Block Predefinito

È buona pratica avere un server block predefinito che intercetta le richieste per nomi di dominio che non corrispondono a nessun'altra direttiva server_name sul tuo server. Questo impedisce che richieste sconosciute vengano servite dal "primo" host virtuale che Nginx trova, o ti permette di servire una pagina generica "sito non trovato".

Tipicamente, il primo blocco server nel tuo nginx.conf o sites-enabled è implicitamente quello predefinito. Puoi impostarne uno esplicitamente usando default_server:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    server_name _;
    # Il trattino basso `_` è un nome di dominio inesistente che non corrisponderà mai a una richiesta reale.
    # Puoi anche usare localhost.

    root /var/www/default_site/html;
    index index.html;

    location / {
        return 444; # Restituisce un errore 444 specifico di Nginx (nessuna risposta) per host sconosciuti
        # Oppure, servi una pagina di destinazione generica:
        # try_files $uri $uri/ =404;
    }
}

Attenzione: Se definisci un blocco default_server, assicurati che solo un blocco server su una data porta listen abbia il flag default_server, altrimenti Nginx registrerà un avviso.

Proteggere gli Host Virtuali con HTTPS (SSL/TLS)

Per i siti web in produzione, abilitare HTTPS è essenziale. Questo comporta l'ottenimento di un certificato SSL/TLS (es., tramite Let's Encrypt usando Certbot) e la configurazione di Nginx per ascoltare sulla porta 443 con il certificato.

Un tipico blocco server HTTPS si presenta così (dopo aver ottenuto i certificati):

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name example1.com www.example1.com;

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

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

    # Includi altre configurazioni SSL (cifrari, protocolli, ecc.)
    include /etc/nginx/snippets/ssl-params.conf;

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

# Opzionale: Reindirizzamento da HTTP a HTTPS per questo dominio
server {
    listen 80;
    listen [::]:80;
    server_name example1.com www.example1.com;
    return 301 https://$host$request_uri;
}

È comune avere un blocco server HTTP separato il cui unico scopo è reindirizzare tutto il traffico alla sua controparte HTTPS.

Se usi Certbot, potrebbe creare o modificare questi blocchi per te. Questo è comodo, ma dovresti comunque leggere il file risultante. Gli strumenti automatizzati per i certificati a volte aggiungono logiche di reindirizzamento in un punto che non avresti scelto tu stesso, e reindirizzamenti duplicati possono rendere più difficile la risoluzione dei problemi.

Logging per Ogni Sito

Come mostrato negli esempi, dedicare file access_log e error_log separati per ogni host virtuale è una buona pratica. Questo rende significativamente più facile il debug dei problemi e l'analisi del traffico per singoli siti web senza dover setacciare log combinati.

Struttura dei File di Configurazione

Per distribuzioni più grandi, considera di organizzare i tuoi file di configurazione di Nginx in questo modo:

  • nginx.conf: Configurazione principale, include conf.d/*.conf e sites-enabled/*.
  • conf.d/: Impostazioni generali a livello di server (es., Gzip, caching).
  • snippets/: Frammenti di configurazione Nginx riutilizzabili (es., parametri SSL, blocchi location comuni).
  • sites-available/: Blocchi server individuali per ogni sito web.
  • sites-enabled/: Collegamenti simbolici alle configurazioni attive in sites-available/.

Risoluzione dei Problemi Comuni

  • Errore 403 Forbidden: Questo di solito significa che Nginx non ha accesso in lettura ai file o alle directory del tuo sito web. Ricontrolla i permessi di file e directory (es., sudo chmod -R 755 /var/www/tuodominio.com/html e assicurati che l'utente Nginx, tipicamente www-data o nginx, possa leggerli).
  • Errore 404 Not Found: Verifica che la direttiva root nel tuo server block punti alla directory corretta e che il tuo file index.html esista in quella posizione. Inoltre, assicurati che try_files sia configurato correttamente.
  • Viene Caricato il Sito Sbagliato: Questo spesso indica un problema con la direttiva server_name. Assicurati che server_name corrisponda esattamente al nome di dominio che stai cercando di raggiungere (inclusi www. o sottodomini). Controlla anche i tuoi record DNS.
  • Nginx non si Avvia/Ricarica: Usa sempre sudo nginx -t per testare la tua configurazione prima di tentare di ricaricare o riavviare Nginx. I messaggi di errore indicheranno la riga e il file in cui si è verificato l'errore di sintassi.
  • Problemi DNS: Se puoi accedere al tuo sito tramite indirizzo IP ma non tramite nome di dominio, è quasi certamente un problema DNS. Usa dig o nslookup per verificare che i record A del tuo dominio puntino all'IP corretto del server.

Test Prima che il DNS sia Pronto

Non devi aspettare il DNS pubblico per testare la parte Nginx. Puoi inviare una richiesta con un header Host personalizzato:

curl -H "Host: example1.com" http://203.0.113.10/
curl -H "Host: example2.com" http://203.0.113.10/

Sostituisci 203.0.113.10 con l'IP del tuo server. Se ogni comando restituisce la pagina di test corretta, la corrispondenza del server block funziona. Se entrambi i comandi restituiscono la stessa pagina, controlla se entrambi i file sono abilitati, se server_name è corretto e se un blocco predefinito sta intercettando la richiesta.

Per HTTPS, il test è leggermente diverso perché TLS usa SNI prima che l'header HTTP Host venga elaborato:

curl --resolve example1.com:443:203.0.113.10 https://example1.com/

Questo comando dice a curl di connettersi all'IP del tuo server usando comunque example1.com per TLS e HTTP. È uno dei modi più rapidi per testare un nuovo host virtuale HTTPS prima di modificare il DNS.

Un Pattern Multi-Sito Manutenibile

Per una manciata di siti statici, gli esempi sopra sono sufficienti. Una volta che ospiti diverse applicazioni, ripeti meno e centralizza solo le parti che sono veramente condivise. Ad esempio, metti gli header di sicurezza comuni, la compressione e i parametri SSL in snippets, ma mantieni root, server_name, upstream e log di ogni sito visibili nel suo file.

Evita di copiare un grande blocco di produzione da un dominio all'altro senza leggere ogni riga. È così che si insinuano errori in server_name, percorsi di certificati errati e file di log condivisi. Una lista di controllo pratica per la revisione è breve:

  • server_name include ogni hostname che gli utenti digiteranno?
  • root o proxy_pass punta a questo sito, non al precedente?
  • I log di accesso e di errore sono sufficientemente separati per eseguire il debug di questo sito da solo?
  • nginx -t passa prima del ricaricamento?
  • curl -H "Host: ..." o curl --resolve restituisce il sito previsto?

Note Finali

Gli host virtuali di Nginx sono affidabili quando ogni sito ha un server block chiaro, un server_name corretto e un fallback predefinito prevedibile. Mantieni i file noiosi. Testa ogni modifica prima di ricaricare. Usa log dedicati quando i siti sono importanti. La maggior parte dei problemi multi-sito di Nginx diventano facili da risolvere una volta che puoi dimostrare se DNS, TLS/SNI o la corrispondenza del server block è la parte che ha fallito.