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 !