Nginx in tutta la sua potenza

Parole Marco Bellomo
Immagini Michael Reali
Tempo di lettura 5

Nginx, ripassiamo alcuni aspetti teorici per usarlo al meglio

P

Come sempre succede, la leggibilità e la facilità possono averci fatto non apprezzare alcuni concetti importanti, che abbiamo subito interiorizzato ma che non abbiamo concettualizzato, un po’ come se, nel passaggio dall’età infantile a quella adolescenziale, ci fossimo trovati subito a pedalare su una bici nuova fiammante, di modello diverso da quello che usavamo fino al giorno prima, e non avessimo fatto attenzione al fatto che i freni sono di tipo diverso, sui pedali si può fare un po’ meno forza, etc, etc ...

Partiamo quindi con alcuni concetti fondamentali 

In Nginx, ogni area di competenza delle nostre definizioni è definita da parentesi graffe. Possono quindi essere logicamente separate o innestate più aree di competenza nei nostri file di configurazione, e ognuna sarà ben separata dall’altra da parentesi graffe.

La separazione o l’innestamento di aree diverse diventa così molto facile da comprendere a una prima occhiata. Ogni “area di competenza” è definita Context.

Data questa bellissima definizione, mi correggo già un po’ partendo dal primo context, il Main

Main Context

Il main context infatti è al di fuori delle parentesi graffe e definisce un primo livello di astrazione dal “fuori” al “dentro”

# Il main context è qui, oltre le frontiere delle nostre amate graffe

. . .
user       www www;  ## attenzione a questo parametro, definisce quale user gruppo può eseguire 
worker_processes  1;  ## valore di default
context {
   # . . .questo è tecnicamente un context
}

 

Nel main context sono definite le direttive che implicano direttive globali inerenti l’applicativo che andiamo a settare. Le direttive più tipiche, sono user e gruppo a cui è permesso eseguire l’applicativo o direttive che affinano l’utilizzo della cpu. 

Event Context

Partiamo a descrivere questo context molto particolare, precisando che ce ne può essere solo uno. Qui vengono definite (se dobbiamo o vogliamo fare un lavoro di fino)  meglio alcune particolarità uii worker process e definire quindi alcuni parametri sulla loro gestione delle connessioni.

Potreste trovare un articolo molto interessante su questi aspetti qui

events {
    # events context
    worker_connections 1024;  #valore che possiamo definire di default
}

HTTP Context

Usando Nginx come web server e/o proxy server il context http racchiude un bel po’ di configurazioni, anche innestate in altri blocchi, che definiscono come l’applicativo deve comportarsi con connessioni http e https

http {
    # http context
     #. . .
}

È una buona idea definire dentro il context http access e error log, il tipo di compressione dei file, che probabilmente sarà gzip, e altre definizioni sui tempi considerati giusti per tenere attive le connessioni, etc, etc…

Dentro il http context, troviamo i server context, ecco quindi già una struttura tipica, che magari padroneggiamo benissimo, ma che non abbiamo mai distinto concettualmente in maniera precisa e fine

# main context
#. . .
user       www www;  ## attenzione a questo parametro, definisce quale user gruppo può eseguire 
worker_processes  1;  ## valore di default
events {
	# events context
	worker_connections  1024;  #valore che possiamo definire di default
}
http {
	# http context
	server {
	               # primo bloccoserver
	}
	server {
	               # secondo blocco server
	}
}

Ogni blocco server può essere usato per definire un virtual host. Dentro ogni blocco server, come sappiamo, tra le cose che facilmente vi troveremo, possiamo ricordate un listen, che indica su quale porta andiamo a intercettare le richieste e il server_name e  cioè il nome del virtual host

server {
	listen 80;
	server_name  sitocasuale.it;
}
server {
	listen 443 ssl;
	server_name  sitocasuale.it;
}

Se già non lo fate o non avete previsto un meccanismo similare, vi consiglierei di mettere come primo blocco server qualcosa di simile 

server {
	listen 80; 
	return 404;
}

in questa maniera, se vi sfuggisse un record A settato su un ip sbagliato (specie se siete stati un po’ permissivi sul resto delle configurazioni), non dovreste avere brutte sorprese con domini indesiderati che puntano sul vostro stesso sito.  

Veniamo ora al location context.

Location Context

Il location context ci permette di definire con molta precisione e (diciamocelo) creatività il tipo di responso che il web server / proxy server dovrà dare a seconda della richiesta dell’utente.

server {
	listen 80;
	server_name sitocasuale.it;
	location /path {
	}
}

Mettiamo per esempio che si voglia definire una risposta standard per il robots.txt, su un sito che per qualche motivo deve avere i robot bloccati. 

Possiamo usare tranquillamente 

location /robots.txt { 
   return 200 "User-agent: *\nDisallow: /\n"
}

Ovvero ...

server {
	listen 80;
	server_name  sitocasuale.it;
	location /robots.txt {  
		return 200 "User-agent: *\nDisallow: /\n"
	}
}

quando l’utente chiederà quindi http://sitocasuale.it/robots.txt ecco che dall’alto verso il basso, tramite nginx abbiamo definito che su porta 80, per virtualhost sitocasuale.it, alla richiesta del file robots.txt deve essere risposto un 200 con questo contenuto testuale : Disallow : /

In un’ottica di ripasso dei concetti fondamentali, che come ci siamo detti magari abbiamo interiorizzato ma che potremmo non avere chiaro quanto dovremmo, analizziamo queste quattro modalità.

Prefix match

location /test1 { return 200 "ciao solo per 1”; }

entra in gioco con sitocasuale.it/test1

Exact match

location =/test1 { return 200 "ciao solo per 1, e sono molto preciso nel cercare esattamente questa combinazione”; }

entra in gioco con sitocasuale.it/test1 prima del prefix match

Regex match case sensitive

location ~ /test[0-9] { return 200 "ciao da 0 a 9, ma attenzione, maiuscole o minuscole non le sento ”; }

entra in gioco con sitocasuale.it/test1 sitocasuale.it/test2 sitocasuale.it/test3 sitocasuale.it/test4 … fino a sitocasuale.it/test9 

Regex match case insensitive

location ~* /test[0-9] { return 200 "ciao da 0 a 9, e metti pure le maiuscole, car* ” }

entra in gioco con sitocasuale.it/test1 sitocasuale.it/test2  e tanti altri, basta considerare tutte le combinazioni di numeri e maiuscole/minuscole

Quando si scrivono regole con i location, bisogna fare molta attenzione con le priorità, le regex hanno la priorità, per esempio, sul prefix match.

Non scordiamo in questa sede il 

Preferential prefix match

location ~^ /test1 { 

	return 200 " io sovrasto un po’ le regex, e quindi attenzione a come mi usi ”

}

che in pratica è una forma di prefix match sotto steroidi , che sovrasta le regex. 

Quindi, anche se la forma migliore per capire è giocare un po’ con la cosa, possiamo dare questo ordine di priorità 

  • Exact match  
  • Preferential prefix match 
  • Regex match
  • Prefix match

Se magari siamo andati  a volte un po’ di corsa, non fa male tenersi questo schema da qualche parte, perché altrimenti è facile fare dello spaghetti code, e non sarebbe male, se temiamo su qualche progetto di aver fatto un po’ troppo di fretta, rifattorizzare il tutto.

Attenzione alla complessità

Usando Nginx, a volte sfugge la sua complessità, che ci permette quasi di programmare, dato l’uso (per esempio) degli if e delle variabili, che potremmo affrontare nel prossimo articolo.

Un tipico caso di potenzialità da comprendere sono rewrite, che possono essere usate sia come redirect che come rewrite.

Redirect

rewrite ^/ciao.html https://sitocasuale.it/verociao/ permanent;

location /verociao

{

    return 200 "come noti cambia url";

}

o che possono essere usate in maniera molto interessante, per reindirizzare internamente le richieste. 

Rewrite

rewrite ^/ciao.html  /verociao;

location /verociao

{

    return 200 "come noti non cambia url";

}

Nel primo caso abbiamo un cambio di url in cima, nel secondo il cambiamento è tutto interno e non sta a me dire ovviamente la potenza della cosa. 

Ci sono tante cose da dire su Nginx e sul doverlo studiare con attenzione per sfruttarlo al meglio, rimanete su questi canali per altre piccole disamine di questo fantastico strumento!

 

Marco Bellomo

IT Manager

A diciott'anni pensavo che sarei diventato uno scrittore di fama mondiale e che avrei dominato le classifiche con il mio oscuro ciclo fantasy. A ventiquattr'anni pensavo che il PHP fosse immortale. Oggi mi piace non dare nulla per scontato, forse perché ...