Nginx tip & tricks: differenze tra le versioni

Da Webmobili Wiki.
Nessun oggetto della modifica
Riga 1: Riga 1:
Varnish Cache server non supporta SSL perché lo sviluppatore non ha voglia di includerlo (fonte [https://varnish-cache.org/docs/4.1/phk/ssl.html non ha voglia]).<br/>
Per ovviare al problema è necessario installare '''nginx''' , un web-server/reverse-proxy in grado di catturare la chiamata https e redirigerla a Varnish.<br/><br/>
== Procedura per installazione ==
Sulla macchina che ha già VARNISH, <u>installare nginx</u>
<syntaxhighlight>
sudo apt-get install nginx
</syntaxhighlight >
L'installazione andrà a buon fine ma verrà mostrato un errore, nginx non riesce a partire perché Varnish è già attivo sulla porta 80. È necessario configurarlo in modo che accolga solo le richieste https.<br/><br/>
Per prima cosa dobbiamo <u>generare un certificato autofirmato</u>
<syntaxhighlight>
sudo mkdir /etc/nginx/ssl
sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt
</syntaxhighlight >
Alla domanda sul ''common name'' è necessario scrivere il nome della macchina sul dominio (lo stesso di a <code>/etc/hostname</code>). Il certificato generato vale solo 10 anni, cambiare il parametro days a piacimento<br/><br/>
Per quanto riguarda la '''configurazione generale di Nginx''' conviene aggiungere 3 parametri che aumentano il tempo di timeout delle pagine quando sono sotto reverse-proxy dentro alla sezione ''http { ... }'' di <code>/etc/nginx/nginx.conf</code>
<syntaxhighlight lang="bash">
##
# Reverse-Proxy Settings
##
proxy_connect_timeout 900;
proxy_send_timeout 900;
proxy_read_timeout 900;
send_timeout 900;
</syntaxhighlight><br/>
Ora apriamo la configurazione di nginx e lo <u>istruiamo per rispondere alle richieste https</u>
<syntaxhighlight>
sudo nano /etc/nginx/sites-enabled/default
</syntaxhighlight >
Il seguente è la configurazione del server di test BRUNOPROXY,
il valore di <code>server_name</code> deve corrispondere con il ''common name'' che è stato dato al certificato.
<syntaxhighlight lang="bash">
# Default server configuration
#
server {
# listen 80 default_server;
# listen [::]:80 default_server;
# SSL configuration
#
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
#root /var/www/html;
# Add index.php to the list if you are using PHP
# index index.html index.htm index.nginx-debian.html;
server_name POCAHONTAS;
ssl_certificate /etc/nginx/ssl/pocahontas.crt;
ssl_certificate_key /etc/nginx/ssl/pocahontas.key;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
#try_files $uri $uri/ =404;
proxy_pass http://127.0.0.1:80;
proxy_set_header X-Real-IP  $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Host $host;
}
}
</syntaxhighlight>
Ora tutte le richieste HTTPS passano da nginx che a sua volta le rigira a Varnish sulla porta 80 (riga <code>proxy_pass <nowiki>http://127.0.0.1:80</nowiki></code>). Vengono servite col certificato autofirmato che non deve essere usato in ambiente di produzione.<br/><br/>
Facciamo un <u>restart di ngix</u>
<syntaxhighlight lang="bash">
sudo service nginx start
</syntaxhighlight>
e per testare andare su <code><nowiki>https://IPPUBBLICO</nowiki></code>.
In caso di Varnish che punta a Windows si arriverà all'IIS. Non è necessario configurare IIS con SSL, possono essere tutti normali websites.<br/><br/>
== Aggiungere domini certificati ==
Per creare un VirtualHost con certificato autentico aggiungere un file dentro alla cartella <code>/etc/nginx/sites-available</code> con la configurazione personalizzata che utilizzi i certificati giusti.
Per renderlo disponibile creare un symlink dentro alla cartella <code>/etc/nginx/sites-enabled</code> e restartare nginx.<br/><br/>
Esempio pratico:
* Copiare i file del certificato (crt e key) + il <u>certificato intermedio</u> nella cartella <code>/etc/nginx/ssl/</code>. N.B. Se si dispone del file .cer basta rinominare l'estensione in .crt
* Unire certificato e certificato intermedio in un unico file con il comando
<syntaxhighlight lang="bash">
cat nomesito.com_ssl_certificate.crt nomesito.com_ssl_certificate_intermediate.crt >> nomesito.com_ssl_certificate_bundle.crt
</syntaxhighlight>
Ricordarsi di mettere in <code>/etc/nginx/ssl/</code> i tre file
* <code>nomesito.com_ssl_certificate.crt</code>
* <code>nomesito.com_private_key.key</code>
* <code>nomesito.com_ssl_certificate_bundle.crt</code>
<br/>
Per il momento su MULAN c'è solo designbest.com .<br/>
wm4pr.com è settato ma non usato. In uso in Test su POCAHONTAS.
<br/><br/>
* Creare il virtual host
<syntaxhighlight lang="bash">
sudo touch /etc/nginx/sites-available/nomesito.com
sudo nano /etc/nginx/sites-available/nomesito.com
</syntaxhighlight>
e scriverci dentro qualcosa come
<syntaxhighlight lang="bash">
server {
listen 443;
ssl on;
ssl_certificate /etc/nginx/ssl/nomesito.com_ssl_certificate_bundle.crt;
ssl_certificate_key /etc/nginx/ssl/nomesito.com_ssl_certificate.key;
server_name nomesito.com;
location / {
proxy_pass http://127.0.0.1:80;
proxy_set_header X-Real-IP  $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Host $host;
}
}
</syntaxhighlight><br/>
* Pubblicare il virtual host su nginx
<syntaxhighlight lang="bash">
sudo ln -s /etc/nginx/sites-available/nomesito.com /etc/nginx/sites-enabled
sudo service nginx restart
</syntaxhighlight><br/><br/>
Verificare la validità del certificato su siti come questo:
[https://www.digicert.com/help/ SSL Certificate Checker]
== Forward dell'IP reale del client ==
== Forward dell'IP reale del client ==
Per la natura dell'infrastruttura server, l'IP reale del client viene perso dopo la chiamata a Nginx.<br/>
Per la natura dell'infrastruttura server, l'IP reale del client viene perso dopo la chiamata a Nginx.<br/>
Riga 157: Riga 21:
#...
#...
</syntaxhighlight>
</syntaxhighlight>
=== Forward di Varnish ===
Nel file di configurazione <code>/etc/varnish/default.vcl</code> piazzare queste righe
<syntaxhighlight lang="c">
sub vcl_recv {
  # Setta l'IP reale del client e lo forwarda
  set req.http.X-Actual-IP = regsub(req.http.X-Forwarded-For, "[, ].*$", "");
  set req.http.X-Forwarded-For = req.http.X-Actual-IP;
  #...
</syntaxhighlight>
== Redirect http to https ==
Per colpa della configurazione del routing il redirect verso https '''non può essere fatto a livello applicativo'''.<br/>
Infatti succederebbe la seguente cosa:
# La chiamata <code>http</code> arriva al <code>''Varnish''</code>
# <code>''Varnish''</code> la dirotta verso la macchina Win con <code>''IIS''</code>
# <code>''IIS''</code> dal suo rewriter trasforma la richiesta in <code>https</code>
# Il giro ricomincia passando questa volta da <code>''Nginx''</code>
# Da qui si torna a <code>''Varnish''</code>, il quale non sapendo gestire una richiesta <code>https</code>, dirotta una normale richiesta <code>http</code> alla macchina Win con <code>''IIS''</code>
# <code>''IIS''</code> dal suo rewriter trasforma la richiesta in <code>https</code> e sitorna al punto '''4'''. generando un <u>loop infinito</u>
[[File:Reverse-Proxy_Infrastructure.jpg]]
<br/><br/>
'''SOLUZIONE''': <br/>
La gestione del <u>redirect verso HTTPS</u> dev'essere affidata a <code>''Varnish''</code>.<br/>
Dentro al file <code>/etc/varnish/default.vlc</code> aggiungere queste 2 parti di codice
<syntaxhighlight lang="bash">
sub vcl_recv {
  # ...
  # Gestione redirect Https
  if(req.http.X-Forwarded-Proto !~ "(?i)https") {
    set req.http.location = "https://" + req.http.host + req.url;
    return (synth(750, "Permanently moved"));
  }
  # altri contenuti
}
sub vcl_synth {
  # ... altri contenuti
  else if(resp.status == 750) {
    set resp.http.Location = "https://" + req.http.host + req.url;
    set resp.status = 301;
    return (deliver);
  }
}
</syntaxhighlight>
In questo modo si evita il loop infinito. '''IMPORTANTE''' ricordarsi che dev'essere <code>''Varnish''</code> ad occuparsi del redirect https, mai l'applicativo.<br/>
Ringrazio [https://www.rsreese.com/redirect-http-to-https-using-varnish/ Stephen Reese] per le info di questa guida.


== Leggere i LOG del web-server ==
== Leggere i LOG del web-server ==
Riga 228: Riga 37:
   sudo adduser nomeutente adm
   sudo adduser nomeutente adm
</syntaxhighlight>
</syntaxhighlight>


== LOG configurazione avanzata ==
== LOG configurazione avanzata ==
Riga 292: Riga 100:
</syntaxhighlight>
</syntaxhighlight>


== Ci togliamo dai coglioni Varnish ==
A causa dell'incapacità di Varnish di gestire https ci siamo rotti i coglioni e vogliamo eliminarlo a favore del solo NGINX.<br/>
L'unica cosa che ci tiene legati a Varnish è il fottuto scudo che ci difende dagli attacchi DDOS.<br/>
Questa guida mostra come NGINX può integrare lo scudo di fatto sfanculando Varnish.<br/>
* https://www.nginx.com/blog/rate-limiting-nginx/
* https://www.youtube.com/watch?v=V9XGT7hvwWo
* https://docs.nginx.com/nginx/admin-guide/security-controls/securing-http-traffic-upstream/<br/>
* '''/etc/nginx/sites-available/dbdemo47.com'''
<syntaxhighlight lang="bash">
upstream www.dbdemo47.com {
server 192.168.250.20:443;
}
upstream dbdemo47.com {
server 192.168.250.20:80;
}
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
##
# DBDEMO47.COM
#
server {
listen 80;
server_name dbdemo47.com www.dbdemo47.com;
access_log /var/log/nginx/dbdemo47.com/access.log;
error_log /var/log/nginx/dbdemo47.com/error.log;
location ~ ^/(it|fr|de|en) {
limit_req zone=mylimit burst=20 nodelay;
        proxy_pass http://dbdemo47.com;
include /etc/nginx/proxy_params;
}
location / {
proxy_pass http://dbdemo47.com;
include /etc/nginx/proxy_params;
}
}
server {
# SSL configuration
#
listen 443 ssl;
listen [::]:443 ssl;
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
#root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name dbdemo47.com www.dbdemo47.com;
ssl_certificate /etc/nginx/ssl/dbdemo47.com_ssl_certificate_bundle.crt;
ssl_certificate_key /etc/nginx/ssl/dbdemo47.com_private_key.key;
access_log /var/log/nginx/dbdemo47.com/access.log;
error_log /var/log/nginx/dbdemo47.com/error.log;
location ~ ^/(it|fr|de|en) {
limit_req zone=mylimit burst=20 nodelay;
proxy_ssl_server_name on;
proxy_pass https://www.dbdemo47.com;
include /etc/nginx/proxy_params;
}
location / {
proxy_ssl_server_name on;
proxy_pass https://www.dbdemo47.com;
include /etc/nginx/proxy_params;
}
}
</syntaxhighlight>
Verificando che il contenuto di <code>/etc/nginx/proxy_params</code> sia
<syntaxhighlight lang="bash">
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
</syntaxhighlight>


[[Category:IT]]
[[Category:IT]]
[[Category:Linux]]
[[Category:Linux]]

Versione delle 15:30, 15 feb 2024

Forward dell'IP reale del client

Per la natura dell'infrastruttura server, l'IP reale del client viene perso dopo la chiamata a Nginx.
Il giro è
Client -> Nginx -> Varnish -> IIS
di conseguenza ad IIS arriva come client IP quello del Varnish e la geolocalizzazione va a puttane
Per sistemare il problema il dato dev'essere passato tramite le varie request all'interno di un header specializzato: X-FORWARDED-FOR.

Forward di Nginx

Essendo il primo punto di passaggio è l'unico che possiede il reale client-IP. Nella configurazione vista del paragrafo precedente si vede l'assegnazione del client-IP nel req header X-FORWARDED-FOR.

#...
location / {
  proxy_pass http://127.0.0.1:80;
  # Set di un header X-Real-IP che serve a varnish
  proxy_set_header X-Real-IP  $remote_addr;
  # Set dell'header X-Forwarded-For per conservare il real IP tramite le varie request che portano ad IIS
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto https;
  proxy_set_header X-Forwarded-Port 443;
  proxy_set_header Host $host;
}
#...

Leggere i LOG del web-server

Purtroppo i log non potranno più essere letti comodamente dall'IIS di Windows perché davanti a lui c'è nginx.
Il consiglio è quello di creare uno share in Samba come questo

[NginxLogs]
  comment = Cartella di condivisione dei log di nginx
  read only = yes
  locking = no
  path = /var/log/nginx
  guest ok = no

e di rendere il proprio utente facente parte del gruppo adm affinché abbia i permessi di lettura.

  sudo adduser nomeutente adm

LOG configurazione avanzata

Avendo diversi siti su Nginx bisogna dividere i log nelle cartelle
es.

/media/discodati/logs/nomesito1.com
/media/discodati/logs/nomesito2.it
/media/discodati/logs/immagini.sito2.com

assicurandosi di mettere i permessi adatti
es.

sudo chown www-data:adm /media/discodati/logs -R
sudo chmod 775 /media/discodati/logs -R


E di conseguenza configurare i singoli virtual host con la cartella giusta

server {

        # ...
	
	server_name nomesito.com;

        error_log /media/discodati/nomesito.com/error.log;
        access_log /media/discodati/nomesito.com/access.log;

        # ...
}


A questo punto tutti i log verranno riversati nei 2 file error.log e access.log.
Per fare in modo che vengano divisi e compressi (una volta che diventano vecchi) automaticamente è necessario configurare LOGROTATE.

sudo nano /etc/logrotate.d/nginx

e modificare come da esempio

/var/log/nginx/*.log /media/discodati/logs/*/*.log {
	su www-data adm
	daily
	missingok
	rotate 14
	compress
	delaycompress
	notifempty
	create 0640 www-data adm
	sharedscripts
	prerotate
		if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
			run-parts /etc/logrotate.d/httpd-prerotate; \
		fi \
	endscript
	postrotate
		invoke-rc.d nginx rotate >/dev/null 2>&1
	endscript
}

Per forzare il logrotate usare

sudo logrotate -f /etc/logrotate.d/nginx