f in x
Nginx da zero: installazione, configurazione base e virtual host — Guida operativa per sviluppatori
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Analisi dei dati e metriche

Nginx da zero: installazione, configurazione base e virtual host — Guida operativa per sviluppatori

[2026-06-02] Author: Ing. Calogero Bono

Il server web è la porta d'ingresso del tuo sito. Se lo configuri male, tutto il resto — codice perfetto, database ottimizzato, CDN — è sprecato. Lo vediamo ogni giorno da sviluppatori che ci portano progetti su VPS: Nginx installato con i default di Ubuntu, un solo virtual host che serve tutto, permessi sballati, log disabilitati. E poi si chiedono perché il sito è lento o cade con 50 visitatori contemporanei.

Noi, di Meteora Web, lavoriamo con Nginx dal 2017. Lo usiamo per siti WordPress trafficati, piattaforme Laravel, e-commerce WooCommerce, e gestiamo da terminale ogni singolo parametro. In questa guida ti portiamo dritto al punto: installazione pulita, configurazione di base solida, virtual host (server block) per servire più domini. Niente fronzoli. Solo ciò che ti serve per mettere in produzione un server web professionale.

Perché Nginx e non Apache (o altro)

Nginx nasce per risolvere il problema C10K — gestire diecimila connessioni contemporanee con un consumo di risorse minimo. A differenza di Apache, che genera un thread o processo per ogni connessione, Nginx usa un modello asincrono e event-driven. Il risultato: con la stessa RAM, Nginx serve dalle 2 alle 5 volte più richieste. Per noi, che abbiamo clienti con picchi di traffico stagionali (Black Friday, saldi di fine stagione), questa differenza si traduce in server che non vanno in crash e fatturato che non si perde.

In più, Nginx si integra benissimo con PHP-FPM (per WordPress, Laravel, qualsiasi CMS), fa da proxy inverso per applicazioni Node.js o Python, e gestisce SSL/TLS in modo efficiente. È lo standard de facto per siti moderni.

Installazione pulita su Ubuntu/Debian

Partiamo da zero. Supponiamo di avere un VPS fresco (Ubuntu 22.04 o 24.04, Debian 12). Il primo passo è aggiornare i pacchetti e installare Nginx dal repository ufficiale.

sudo apt update
sudo apt upgrade -y
sudo apt install nginx -y

Dopo l'installazione, Nginx parte automaticamente. Verifichiamo:

sudo systemctl status nginx

Dovresti vedere active (running). Se non parte, controlla i log con journalctl -u nginx.

Firewall: aprire le porte giuste

Prima di continuare, assicurati che il firewall (UFW) permetta traffico HTTP e HTTPS:

sudo ufw allow 'Nginx Full'

Questo comando apre le porte 80 e 443. Se usi solo HTTP per test, basta sudo ufw allow 'Nginx HTTP'.

A questo punto, visitando l'IP pubblico del server nel browser dovresti vedere la pagina di default di Nginx. Se non la vedi, controlla che il provider cloud non abbia un firewall esterno (es. security group su AWS, firewall su OVH).

Configurazione base di nginx.conf

Il file principale di configurazione è /etc/nginx/nginx.conf. Noi lo apriamo e modifichiamo subito alcuni parametri per adattarlo al carico di lavoro tipico.

sudo nano /etc/nginx/nginx.conf

Ecco una configurazione di partenza solida per un server che ospita uno o più siti web (non per reverse proxy puro):

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 1024;
    # multi_accept on; # sblocca se hai molti keepalive
}

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

    # Log format con tempi di risposta
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    'rt=$request_time uct=$upstream_connect_time uht=$upstream_header_time urt=$upstream_response_time';

    access_log /var/log/nginx/access.log main buffer=32k flush=5s;
    error_log /var/log/nginx/error.log warn;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    # Limitare dimensione upload a 50MB (utile per caricamenti di file)
    client_max_body_size 50M;

    # Gzip per risparmiare banda
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript image/svg+xml;

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

Spieghiamo le scelte chiave:

  • worker_processes auto: Nginx imposta il numero di worker process pari al numero di core CPU. Per la maggior parte dei VPS (1-4 core) è perfetto.
  • worker_connections 1024: connessioni massime per worker. In totale server può gestire worker_processes * worker_connections = 4 * 1024 = 4096 connessioni contemporanee. Abbastanza per iniziare.
  • gzip: comprime il testo prima di inviarlo al browser. Riduce il peso delle risorse del 50-70%.
  • client_max_body_size 50M: ti evita errori 413 quando carichi immagini o backup via web. Abbiamo visto clienti con modulo contatti che non accettava allegati perché il default era 1M.

Dopo aver modificato, testa la sintassi:

sudo nginx -t

Se tutto OK, ricarica la configurazione senza downtime:

sudo systemctl reload nginx

Virtual Host (Server Block): servire più siti con un solo Nginx

La vera potenza di Nginx è nei server block — l'equivalente dei VirtualHost di Apache. Ogni server block definisce come rispondere a un determinato dominio. Noi organizziamo i file in /etc/nginx/sites-available/ (configurazioni disponibili) e creiamo link simbolici in /etc/nginx/sites-enabled/ per attivarle.

Struttura standard

Per ogni dominio che ospitiamo, creiamo un file come questo:

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

    server_name esempio.it www.esempio.it;

    root /var/www/esempio.it/public;
    index index.php index.html index.htm;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }

    # Log per questo sito
    access_log /var/log/nginx/esempio.it_access.log main buffer=32k flush=5s;
    error_log /var/log/nginx/esempio.it_error.log warn;
}

Analizziamo ogni direttiva:

  • server_name: i domini che questo blocco serve. Puoi usare wildcard come *.esempio.it.
  • root: directory da cui servire i file. Importante: Nginx non segue i symlink di default (ma va bene così per sicurezza).
  • location /: tenta di servire il file esatto ($uri) o la directory ($uri/), altrimenti riscrive tutto a index.php. È il pattern standard per WordPress, Laravel e Symfony.
  • location ~ \.php$: passa i file PHP a PHP-FPM tramite socket Unix. Più veloce della porta TCP.
  • location ~ /\.ht: blocca l'accesso ai file .htaccess (Nginx non li legge, ma è buona norma nasconderli).

Attivare un sito

Salva il file come esempio.it in /etc/nginx/sites-available/. Poi:

sudo ln -s /etc/nginx/sites-available/esempio.it /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Se vuoi disattivare un sito, basta rimuovere il link: sudo rm /etc/nginx/sites-enabled/esempio.it e ricaricare.

Esempio pratico: due siti sullo stesso server

Immagina di avere due progetti: un e-commerce (negozio.it) e un blog (blog.it). Crei due file separati in sites-available. Il primo:

# /etc/nginx/sites-available/negozio.it
server {
    listen 80;
    server_name negozio.it www.negozio.it;
    root /var/www/negozio.it;
    index index.php index.html;
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        include snippets/fastcgi-php.conf;
    }
    access_log /var/log/nginx/negozio.it_access.log;
    error_log /var/log/nginx/negozio.it_error.log;
}

Il secondo:

# /etc/nginx/sites-available/blog.it
server {
    listen 80;
    server_name blog.it www.blog.it;
    root /var/www/blog.it/public;
    index index.php index.html;
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        include snippets/fastcgi-php.conf;
    }
    access_log /var/log/nginx/blog.it_access.log;
    error_log /var/log/nginx/blog.it_error.log;
}

Attiviamo entrambi:

sudo ln -s /etc/nginx/sites-available/negozio.it /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/blog.it /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Ora, quando un browser chiama negozio.it, Nginx risponde con il contenuto di /var/www/negozio.it; per blog.it con /var/www/blog.it/public. Pulito e isolato.

Errori comuni e come risolverli

Permessi sbagliati sulla root

Uno degli errori più frequenti: il server block punta a una directory che Nginx (utente www-data) non può leggere. Risultato: 403 Forbidden. Soluzione: assicurati che l'utente www-data abbia almeno permessi di lettura ed esecuzione sulla directory e sui file. Noi di solito facciamo:

sudo chown -R www-data:www-data /var/www/miosito
sudo find /var/www/miosito -type d -exec chmod 755 {} \;
sudo find /var/www/miosito -type f -exec chmod 644 {} \;

Se il sito scrive file (es. upload di WordPress), dai permessi di scrittura solo alla directory necessaria:

sudo chmod 775 /var/www/miosito/wp-content/uploads

Server block non attivo

Hai creato il file in sites-available ma dimenticato il link simbolico in sites-enabled. Nginx ignora il file. Controlla sempre con ls -la /etc/nginx/sites-enabled/.

Nome server non risolto

Se visiti il dominio e finisci sulla pagina di default di Nginx (o su un altro sito), probabilmente il server_name non corrisponde a quello che stai chiamando. Può succedere se hai un server block di default senza server_name che cattura tutto. Noi raccomandiamo di disabilitare il default:

sudo rm /etc/nginx/sites-enabled/default

L'alternativa è creare un server block catch-all che restituisce 444 (nessuna risposta):

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 444;
}

File PHP scaricati invece di essere eseguiti

Succede quando manca il blocco per i file PHP, o il socket di PHP-FPM non è attivo. Controlla che php8.3-fpm.sock esista (ls /var/run/php/) e che il servizio sia in esecuzione (sudo systemctl status php8.3-fpm).

In sintesi — cosa fare adesso

Hai le basi per mettere in produzione un server Nginx con configurazione solida e virtual host multipli. Non fermarti qui: i prossimi passi sono SSL con Let's Encrypt (certbot), hardening della configurazione, caching delle risorse statiche, e monitoraggio.

  1. Installa Nginx su un VPS di prova (DigitalOcean, Hetzner, o locale con Vagrant).
  2. Applica la configurazione di base che ti abbiamo dato, testala con nginx -t.
  3. Crea due server block per due domini (anche finti, modificando il file hosts locale). Verifica che rispondano correttamente.
  4. Abilita i log differenziati per ogni sito, così puoi diagnosticare problemi specifici.
  5. Imposta permessi corretti per le directory dei siti.

Se lavori con microservizi o architetture complesse, il nostro articolo su Microservizi vs Monolite ti aiuterà a capire quando Nginx come reverse proxy è la scelta giusta. Per approfondire il monitoraggio, leggi la guida ai tre pilastri dell'observability.

Un server web configurato bene è come un magazzino ordinato: trovi tutto, non si rompe nulla, e lavori il doppio. Come diciamo sempre: un server non è una scatola nera, è la fondazione del tuo business digitale. Trattalo come tale.

Sponsored Protocol

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Co-founder di Meteora Web. Ingegnere informatico, sviluppo ecosistemi digitali ad alte prestazioni. AI, automazione, SEO tecnica e infrastrutture web. Scrivo di tecnologia per rendere complesso… semplice.

[ Read Full Dossier ]

Hai bisogno di applicare questa strategia?

Esegui il protocollo di contatto per iniziare un progetto con noi.

> INIZIA_PROGETTO

Sponsored

> MW_JOURNAL

> READ_ALL()