Un’infrastruttura virtualizzata e modulare per servizi web con ProxMox, Nginx e Varnish

 

Stato di progetto

Mi è stato chiesto di ottimizzare diversi siti web preesistenti, per la maggior parte WordPress, consolidando l’infrastruttura su un solo server, in cloud, fornito dal proprietario dei siti stessi, cercando di tenerli separati in base a criteri forniti in sede di analisi.
Il server messo a disposizione è un server fisico della linea SoYouStart di OVH (https://www.soyoustart.com/it/), con queste caratteristiche hardware: Processore Xeon E3-1225v2, 32GB RAM, Storage composto da 3x120GB SSD in RAID 5 software.
Per poter garantire la separazione richiesta e anche una certa flessibilità in vista di eventuali sviluppi futuri si è optato per una architettura con un sistema di virtualizzazione al cui interno procedere poi alla creazione degli ambienti server con i vari siti. Pertanto, scegliendo dal catalogo proposto dal provider, si è scelto di far installare (a cura di OVH) ProxMox VE 5.1.

Configurazione dell’ambiente di rete

L’offerta di OVH prevede di serie un solo IP pubblico e non era possibile (per volontà del proprietario) aggiungerne altri. Per questo motivo era necessario provvedere ad un sistema, posto davanti agli altri, che ricevesse le richieste e le filtrasse in base alla URL. La scelta architetturale prevede quindi la creazione, all’interno dell’ambiente ProxMox, di una rete virtuale nella quale mettere i server ospitati e la gestione del routing attraverso il server host.
ProxMox è basato su Debian e quindi è possibile aggiungere o rimuovere i pacchetti usando semplicemente apt-get. Quindi per prima cosa installiamo il pacchetto Open Vswitch, per creare gli switch virtuali:

apt-get install openvswitch-switch

A questo punto si può creare un nuovo Bridge OVS che useremo per definire la rete interna all’hypervisor nella quale mettere le macchine. Questa operazione è piuttosto semplice, in quanto si fa dall’interfaccia grafica di ProxMox:

Schermata del 2018-05-21 11-40-56

Il nome (vmbrX) viene assegnato dal sistema automaticamente. L’indirizzamento di rete può essere scelto a piacere, così come la subnet (di solito una /24 è sufficiente)
Una volta creata la subnet occorre fare alcuni interventi sulla configurazione di rete dell’hypervisor per permetter il traffico tra lo stesso e le macchine ospitate al suo interno nella sottorete che abbiamo appena creato.
Procediamo quindi ad editare il file /etc/network/interfaces sull’hypervisor, utilizzando l’editor che preferiamo. All’interno del file troveremo delle interfacce denominate vmbrX. Cerchiamo quella che abbiamo creato prima dall’interfaccia grafica, senza toccare le altre (I numeri di riga sono stati inseriti solo per facilitare la comprensione, nel file ovviamente non ci sono).

auto vmbr3
1 iface vmbr3 inet static
2 address 10.0.0.254
3 netmask 255.255.255.0
4 ovs_type OVSBridge
5 post-up echo 1 > /proc/sys/net/ipv4/ip_forward
6 post-up iptables -t nat -A POSTROUTING -s ‘10.0.0.0/24’ -o vmbr0 -j MASQUERADE
7 post-down iptables -t nat -D POSTROUTING -s ‘10.0.0.0/24’ -o vmbr0 -j MASQUERADE
8 post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp –dport 443 -j DNAT –to 10.0.0.1:443
9 post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp –dport 443 -j DNAT –to 10.0.0.1:443
10 post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp –dport 80 -j DNAT –to 10.0.0.1:80
11 post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp –dport 80 -j DNAT –to 10.0.0.1:80

Vediamo cosa contengono le righe appena create:
Le righe dalla uno alla quattro contengono la definizione della rete e dovremmo trovarle nel file (vengono inserite nel momento della creazione della rete dallinterfaccia grafica);
la riga cinque imposta il forward dei pacchetti. In pratica abilita tutto ciò che è specificato dopo.
Tutte le righe che seguono sono in realtà doppie perchè prevedono il comando sia per l’avvio (post-up) che per lo spegnimento (post-down). In tutte è citata, come interfaccia di ingresso e uscita l’interfaccia principale del server, quella su cui è attestato l’IP pubblico. Solitamente prende il nome vmbr0. Comunque nel file la si può identificare facilmente.
Le righe 6 e 7 definiscono il routing in uscita, ovvero consentono al traffico proveniente dalla sottorete dei server di uscire verso Internet;
Le righe 8 e 9 definiscono il NAT della porta 443 (HTTPS) da Internet verso il server virtuale che riceve le connessioni e le smista sui veri webserver, mentre le righe 10 e 11 fanno la stessa cosa per la porta 80 (HTTP).
Se dovessero servire altre porte basta ripetere la stessa cosa con il numero di porta corretto. L’indirizzo 10.0.0.1 è quello che sarà poi assegnato al server che svolgerà il ruolo di front end

La parte di configurazione della rete è finita. Riavviamo il server ProxMox.

I server virtuali

ProxMox offre al suo interno due tecnologie di virtualizzazione: i cosiddetti Linux containers oppure la più tradizionale virtualizzazione KVM.
Non è scopo di questo articolo spiegare le differenze tra le due tecnologie. Per approfondire i concetti potete leggere la documentazione di ProxMox qua.
I container LXC permettono delle ottime prestazioni e un uso limitato di risorse, a fronte di alcuni vincoli architetturali ben precisi. La tecnologia KVM, al contrario, consente di avere una virtualizzazione più simile a quella di noti prodotti commerciali, con una maggior flessibilità di configurazione a fronte di una richiesta di risorse più elevata.
I container LXC si installano attraverso i cosiddetti “template” ovvero dei pacchetti già pronti che possono essere scaricati dalla rete direttamente tramite l’interfaccia grafica di ProxMox e che comprendono le più comuni distribuzioni di Linux

Il server di front end

Il server di front end è stato realizzato con la tecnologia LXC. La distribuzione utilizzata è Debian 9 Stretch. Basta scaricare il template di Debian 9 a 64 bit dall’interfaccia grafica e installarlo e ci si troverà con poche configurazioni il server pronto.
Per quanto riguarda il software da utilizzare, esso deve rispondere alle seguenti esigenze:
1) consentire lo smistamento delle chiamate in base all’URL
2) gestire il traffico SSL
3) ottimizzare le prestazioni
Un singolo software Open Source che abbia tutte queste caratteristiche non esiste; occorre quindi utilizzarne due che interagiscano tra di loro.
Per i primi due punti, scartato Pound (http://www.pound.ch), di ottima fattura, ma piuttosto datato e non semplice da usare in SSL si è optato per Nginx (https://www.nginx.com/), configurato come reverse proxy. Questo software, ormai molto diffuso, permette di gestire le chiamate, dividendo i siti in HTTPS da quelli in HTTP semplice, fare l’offloading dei certificati e ridirigere le chiamate. Potrebbe bastare anche da solo per gestire la redirezione, ma si è preferito accoppiarlo a Varnish (https://varnish-cache.org/) per migliorare le prestazioni.
Vediamo come.

Nginx e i certificati SSL

I siti ospitati nel sistema sono in parte in HTTP semplice, in parte in HTTPS (con la redirezione, ovvero se si digita la pagina in http si viene rimandati in HTTPS), in parte misti (cioè HTTP e HTTPS convivono). I certificati usati sono tutti emessi da LetsEncrypt (https://letsencrypt.org/). Visto che Varnish non gestisce in alcun modo l’HTTPS è necessario  che i certificati siano gestititi da Nginx, lasciando poi in chiaro tutto il traffico, verso Varnish e anche verso i server di backend.
Letsencrypt fornisce un ottimo sistema per gestire i certificati, denominato Certbot, che provvede a generare i certificati ed eventualmente modificare i files di configurazione per effettuare la redirect da HTTP ad HTTPS
Sul sito di Certbot (https://certbot.eff.org/) basta selezionare il webserver e il sistema operativo usati e il sito provvede a fornire le istruzioni necessarie per l’installazione. Nel nostro caso (Nginx su Debian 9) occorre prima di tutto aggiungere i backports di Debian, aggiungendo al file /etc/apt/sources.list la seguente riga:

deb http://ftp.debian.org/debian stretch-backports main

Poi aggiornare i repository e installare Cerbot:

apt-get update
apt-get install certbot
Prima di generare i certificati è consigliabile creare i virtualhost su Nginx, facendoli puntare tutti alla directory di default (dove c’è una pagina di cortesia).

Ad esempio:

server {
server_name www.esempio.it;

listen 80 default_server;
listen [::]:80 default_server;

root /var/www/html;
index index.nginx-debian.html;

location / {
try_files $uri $uri/ =404;
}
}

Basta creare nella directory /etc/nginx/sites-available tanti files come quello quanti sono i siti ospitati. Poi, per renderli operativi occorre creare un link simbolico nella directory /etc/nginx/sites-enabled e poi restartare Nginx

ln -s /etc/nginx/sites-available/nomesito /etc/nginx/sites-enabled/nomesito
systemctl restart nginx

Il secondo passo necessario per generare i certificati è che i record DNS pubblici dei siti puntino all’IP del server che stiamo realizzando, altrimenti non sarà possibile completare l’operazione.
Fatto questo basta lanciare Certbot con il seguente comando:

certbot –authenticator webroot –installer nginx

Il software chiede di scegliere il sito per cui generare il certificato (l’operazione va ripetuta per tutti i sit per i quali si vuole attivare l’HTTPS), quindi la webroot directory (inserire il valore della riga che inizia con root nel file di configurazione qua sopra) e infine se si vuole attivare il redirect oppure no. Terminate queste operazioni il sito richiesto avrà l’SSL attivato con il certificato emesso da Letsencrypt.
Ora che abbiamo i nostri siti configurati con Nginx, chi in SSL e chi no, a seconda delle esigenze, occorre far si che le richieste, anziché essere ridirette al sito fittizio che abbiamo usato, vengano inviate a Varnish che si curerà di smistarle per URL ai singoli server di backend, oltre a fare la sua funzione di cache per velocizzare le prestazioni. Prima di tutto configuriamo Nginx per fare la redirect.
I siti in HTTP semplice saranno configurati così:

server {
server_name www.sitoinhttp.it;
#
location / {
proxy_pass http://127.0.0.1:8080;
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 http;
proxy_set_header X-Forwarded-Port 80;
proxy_set_header Host $host;
}
}

Quelli in HTTPS senza redirect così (attenzione: se si vuole far si che il sito risponda anche sulla porta 80 va fatto anche un file come quello qua sopra):

server {
server_name www.sitoinhttpsmisto.net;
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/www.sitoinhttpsmisto.net/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/www.sitoinhttpsmisto.net/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
#
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}

Infine quelli in HTTPS con redirect così:

server {
server_name www.sitoinhttpsconredirect.net;
#
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/www.sitoinhttpsconredirect.net/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/www.sitoinhttpsconredirect.net/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
#}
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
#
server {
if ($host = www.sitoinhttpsconredirect.net) {
return 301 https://$host$request_uri;
} # managed by Certbot

listen 80;
server_name www.sitoinhttpsconredirect.net;
return 404; # managed by Certbot

}

Varnish verrà configurato per ascoltare sulla porta 8080 dell’indirizzo 127.0.0.1. come indicato.
Fatte le modifiche riavviamo nginx un’ultima volta e passiamo a Varnish

Varnish

Nei repository ufficiali di Debian non c’è la versione 5.1 di Varnish, che è quella che invece ci serve. Per installarla bisogna seguire questi passi:
Installare la chiave del repository:

curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | sudo apt-key add –

Poi il keyring e il trasporto di APT per https:

apt-get install -y debian-archive-keyring
apt-get install -y apt-transport-https

Aggiungiamo il repository:

echo “deb https://packagecloud.io/varnishcache/varnish5/debian/ stretch main” | sudo tee -a /etc/apt/sources.list.d/varnishcache5.list

Infine installiamo Varnish:

apt-get update
apt-get install -y varnish

Per avere Varnish configurato per ascoltare sulla porta 8080, come richiesto dalla configurazione di Nginx occorre modificare il file di avvio di systemd (di default Varnish ascolta sulla 6081):

nano /lib/systemd/system/varnish.service

La riga è questa (sostituire 6081 con 8080)

ExecStart=/usr/sbin/varnishd -a :6081 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m

Ricordarsi di ricaricare la configurazione di systemd:

systemctl daemon-reload

Varnish è pilotato da un file di configurazione denominato default.vcl, che andremo ad editare:

nano /etc/varnish/default.vcl

All’interno di questo file dovremo definire i backend (tante righe, una per ogni sito ospitato):

backend sito1 {
.host = “10.0.0.2”;
.port = “80”;
}

Poi, più sotto, nella funzione sub vcl_recv le regole per il filtraggio in base all’URL (anche qua tante righe, una per ogni sito ospitato):

{
if (req.http.host ~ “www.sito1.it”) {
set req.backend_hint = sito1;
}

Attenzione: il valore dei campi backend nel primo blocco deve coincidere esattamente con il valore di set req.backend_hint nel secondo.

Terminata questa operazione la configurazione del nostro server di front end è completa. Quando arriva una richiesta per un sito di quelli ospitati, la stessa viene inoltrata al server di frontend, dove viene gestita da Nginx. Questi, dopo aver eventualmente gestito l’SSL (creando il tunnel) gira la richiesta a Varnish, il quale, in base all’URL della richiesta indirizza la chiamata al server  corretto in backend, trattenendo in cache le risposte, in modo da fornirle più velocemente qualora venissero richieste di nuovo.

I server di backend

I server di backend sono quelli che erogano realmente i siti. Anch’essi sono stati fatti con tecnologia LXC. Ne sono stati fatti diversi, in modo da rispettare la suddivisione voluta dal proprietario. Essendo siti già esistenti ed importati in un paio di casi si è dovuti ricorrere a versioni più vecchie di Debian (una 7 e una 8), per poterne garantire il funzionamento. Questo però è un problema limitato in quanto sui server con i sistemi operativi più vecchi (e quindi potenzialmente soggetti a a problemi di sicurezza) gira solo il sito che lo richiede e non altri, come accadrebbe nel caso di un singolo server monolitico.
Trattandosi per la maggior parte di siti sviluppati con WordPress segnalo il fatto che in questa configurazione, se il sito è in HTTPS si genera un problema di “Contenuto misto non sicuro”. Il problema si risolve installando un apposito plugin su wordpress, come spiegato in diversi articoli rintracciabili in rete.

Utility & Commodity

A margine dell’installazione vera e propria appena spiegata, sono stati predisposti dei servizi di comodo.
1) DNS interno all’infrastruttura: un sistema DNS interno all’infrastruttura permette le chiamate per nome. Il server primario è stato messo su un server usato per siti di test, mentre il secondario è ospitato dal PC Client (v. sotto);
2) Monitoraggio: tutta l’infrastruttura (server fisico compreso) è monitorato tramite un’istanza Zabbix posta altrove. Per questo è stato installato sul server fisico un proxy Zabbix che raccoglie tutti i dati (del server fisico e di quelli virtuali), mentre su ogni server è presente un agente di Zabbix
3) PC Client: per comodità, dovendo spesso fare operazioni di manutenzione possibili solo dall’interno dell’infrastruttura è stato creato un pc virtuale (con tecnologia KVM) all’interno, sul quale è stato installato Lubuntu 19.10, utilizzabile per questi scopi. Questa macchina ospita anche il server DNS secondario.
4) Backup: OVH mette a disposizione, per la sua linea SoYouStart uno spazio di backup gratuito di 100 GB accessibile solo via FTP. Visto che con una cifra irrisoria si può avere l’accesso via NFS si è attivata questa opzione, in modo da fare i backup senza fatica con lo strumento nativo di ProxMox

 

© 2021 Catfish Blog | Tema: Storto di CrestaProject WordPress Themes.