Premier Training & Business Partner Red Hat

configurare nginx – seconda parte

Andrea Manzini
Ti piacerebbe diventare anche tu uno di noi e
pubblicare i tuoi articoli nel blog degli RHCE italiani?

Torniamo a parlare di NGINX, HTTP server leggero e veloce che sta conquistando sempre più consensi tra chi si occupa di servizi web.
Un software efficiente, riuscendo a servire più connessioni con meno risorse, ci garantisce un risparmio in termini di RAM e CPU. Tutto questo si traduce concretamente in costi minori sia per il gestore (datacenter più piccoli, meno macchine) sia per l’utente finale (basta un VPS meno performante e quindi meno costoso).
Inoltre NGINX è progettato per il zero-downtime: grazie all’utilizzo dei segnali unix è possibile persino aggiornare il programma senza alcun disservizio.

DIRETTIVE PROXY
Uno dei tipici casi d’uso di NGINX è come front-end davanti al “vero” application server. Configuriamo un semplice reverse-proxy:

http {
  server {
    location / {
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_pass http://localhost:8080;
    }
    location ~ \.(gif|jpg|png)$ {
       root /data/images;
    }
  }
}

con la prima direttiva location, vediamo come sia possibile modificare gli header HTTP prima di inoltrare la richiesta al webserver destinatario, che in questo caso sarà in ascolto sulla porta 8080 in locale. Ovviamente è possibile passare le richieste anche ad un server remoto semplicemente inserendo il suo indirizzo. Le richieste per immagini statiche, che quindi soddisfano la regexpr della location più sotto, saranno invece servite direttamente dal motore di NGINX. E’ utile sapere che per default le richieste vengono bufferizzate, ma a tal proposito segnaliamo a chi volesse approfondire che esistono anche le direttive di controllo della cache.

VIRTUALHOST

Servire più siti diversi con nginx è facile: si aggiungono tanti blocchi server, ciascuno con la propria root e si usa la direttiva server_name per indicare il dominio a cui dovrà rispondere il sito. Esempio:

http {
  server {
    listen 80 default_server;
    root /home/primosito/public_html;
    index index.html index.htm;
    server_name primosito.com;
    location / {
      try_files $uri $uri/ =404;
    } 
  }
  server {
    listen 80;
    root /home/secondosito/public_html;
    index index.html index.htm;
    server_name secondosito.it www.secondosito.it;
    location / {
      try_files manutenzione.html $uri $uri/ =404;
    } 
  }
}

Possiamo notare che il sito di default, mostrato nel caso in cui contattassimo il server per indirizzo ip, è il primo; mentre puntando il browser al secondo sito (che ha due nomi) visualizzeremo pagine diverse. Abbiamo introdotto la direttiva “try_files” che è molto utile per fornire alternative diverse allo stesso percorso logico nell’URL. Nel nostro esempio, quando l’utente chiama la homepage del sito, viene prima cercato il file manutenzione.html (che creeremo quando vogliamo segnalare lavori sul sito); se non esiste quello, nginx carica e serve il file indicato dall’utente (con due varianti: con e senza slash finale) e infine il classico “404” nel caso la pagina richiesta non venga trovata.
Come nota a margine, ricordiamo che “virtualhost” è un termine del gergo di Apache e in ngix questo tipo di configurazione prende il nome di “server blocks”.

AUTENTICAZIONE

Se vogliamo fare in modo che una certa sezione del nostro sito sia accessibile solo previa digitazione di una password, possiamo configurare una determinata location perché richieda autenticazione:

server {
  listen 80;
  server name dominio.it www.dominio.it;
  root /data/www/html;  #contenuto normale
 
  location /admin {
    auth_basic "Area Riservata";
    auth_basic_user_file /data/www/.htpasswd;
  }
  
  #!!IMPORTANTE!! nega accesso a file nascosti
  location ~ /\. {deny all;}
}

Notiamo in questa nuova configurazione la presenza di un file esterno, chiamato per convenzione .htpasswd (ma andrebbe bene qualsiasi altro nome) che deve contenere le coppie username/password, come potrebbe essere

$ cat /data/www/.htpasswd
admin:saMNhdbYqwtng

per generare password con questo tipo di cifratura possiamo usare dei servizi online, oppure rispolverare il buon vecchio Perl…

$ perl -le 'print crypt("PasswordSegreta", "salt-hash")'

cosa molto importante, il file deve essere leggibile dal demone nginx (controllare quindi i permessi sul filesystem e contesto SELinux) ma non deve assolutamente “uscire” dal webserver: un malintenzionato potrebbe farsi servire il file stesso da nginx e decifrare la password con dei tool di bruteforce. Per evitare questo, inseriamo la riga di deny che inizia con “~” (tilde). Quando NGINX incontra una location con questa sintassi, interpreta la porzione successiva come una regular expression, e se c’è un matching, esegue la direttiva. Nel nostro caso la regexp è semplice: se l’utente chiede qualunque file che inizi con un “.” (il carattere va quotato con una backslash) l’accesso è negato.

PAGINE DINAMICHE
Come testimoniano siti di grande successo , NGINX è un prodotto maturo, adatto non solo come proxy o siti statici ma per gestire contenuti complessi; in questa sezione vediamo come esempio una possibile configurazione per l’onnipresente linguaggio PHP. Iniziamo con l’installazione dei pacchetti necessari:

$ sudo yum -y install php-fpm
[...]
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
[...]
Installato:
  php-fpm.x86_64 0:5.4.16-36.el7_1
Dipendenza installata:
  libzip.x86_64 0:0.10.1-8.el7
  php-common.x86_64 0:5.4.16-36.el7_1                                            
 
Completo!
 
$ sudo systemctl start php-fpm
$ sudo systemctl enable php-fpm
$ systemctl status php-fpm
php-fpm.service - The PHP FastCGI Process Manager
   Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled)
   Active: active (running) since mer 2015-07-15 09:08:43 UTC; 22s ago
 Main PID: 20051 (php-fpm)
   Status: "Processes active: 0, idle: 5, Requests: 0, slow: 0, Traffic: 0req/sec"
   CGroup: /system.slice/php-fpm.service
           ├─20051 php-fpm: master process (/etc/php-fpm.conf)
           ├─20052 php-fpm: pool www
           ├─20053 php-fpm: pool www
           ├─20054 php-fpm: pool www
           ├─20055 php-fpm: pool www
           └─20056 php-fpm: pool www

Nella configurazione diciamo a NGINX che tutte le richieste che finiscono per “.php” vanno dirette al socket locale su cui ascolta php-fpm , il demone FastCGI Process Manager:

 
user nginx;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections  512;
}

http {
  index  index.html;
  server {
    listen  80;
    root /data/www;
    location / {
      try_files $uri $uri/ /index.html;
    }
    location ~ \.php$ {
      fastcgi_index   index.php;
      fastcgi_pass    127.0.0.1:9000;
      #fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock; #abilitare uno o l'altro in caso 
      include         fastcgi_params;
      fastcgi_param   SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    }
  }
}

qui ci torna comoda la direttiva include, perché sfruttiamo un file fornito dal pacchetto nginx che contiene già le associazioni tra i parametri FCGI e le variabili della richiesta esposte dal webserver. Prepariamoci una pagina per capire se venga eseguito correttamente l’interprete PHP:

$ echo '<!--?php phpinfo(); ?-->' |sudo tee /data/www/index.php

e, dopo aver ricaricato la nuova configurazione di NGINX, puntiamo il browser alla pagina di test:

con questo tipo di setup, possiamo gestire qualsiasi tipo di applicazione php, come wordpress.

STATUS
alla pari di Apache, NGINX ha una ricca scelta di moduli extra, sia sviluppati internamente che di terze parti; come dimostrazione, vediamo la possibilità di configurare una pagina di “status” che ci informi sulla “salute” del nostro server:

location /server_status {
  stub_status on;
  access_log off;
  allow 192.168.1.111;
  deny all;
}

visualizzando la pagina /server_status otteniamo una serie di informazioni, la cui descrizione è dettagliata nella documentazione del modulo.

Active connections: 1 
server accepts handled requests
 3 3 4 
Reading: 0 Writing: 1 Waiting: 0 

CONCLUSIONE

Per il momento concludiamo qui la nostra panoramica sulle configurazioni di NGINX; nel prossimo articolo affronteremo altri aspetti… Ma ovviamente accettiamo commenti e proposte !

Info about author

Andrea Manzini