Avendo a disposizione un solo indirizzo IP pubblico, ma diversi servizi web da pubblicare, l’uso di un reverse proxy diventa essenziale.
Nel mio specifico caso, il router inoltra tutto il traffico proveniente da internet, sulle porte 80/tcp e 443/tcp, verso l’indirizzo interno del reverse proxy (lxc debian con apache2); questo si fa carico di capire a chi èindirizzata la richiesta tramite l’uso dei VirtualHost e la “rigira” verso il server virtuale corretto, sulla porta corretta.
Tutto meraviglioso, è il funzionamento normale di un reverse proxy. Se non fosse che un cluster Proxmox ha alcune peculiarita’.
Inanzitutto, è appunto un cluster, ovvero un gruppo di server, non un singolo server. Inoltre fa uso dei WebSockets per offrire la possibilita’ di aprire le console dei server virtuali (e di quelli fisici).
Ma vediamo la configurazione, commentandola dopo, per capire meglio:
root@proxy:~# cd /etc/apache2/sites-available/
root@proxy:/etc/apache2/sites-available# cat pve.conf
<Proxy balancer://pve.xxxxxxxxxxxxxxx.xx>
BalancerMember https://xxx.yyy.zzz.100:8006 ping=50ms timeout=1
BalancerMember https://xxx.yyy.zzz.101:8006 ping=50ms timeout=1
BalancerMember https://xxx.yyy.zzz.102:8006 ping=50ms timeout=1
</Proxy>
<Proxy balancer://wsspve.xxxxxxxxxxxxxxx.xx>
BalancerMember wss://xxx.yyy.zzz.100:8006 ping=50ms timeout=1
BalancerMember wss://xxx.yyy.zzz.101:8006 ping=50ms timeout=1
BalancerMember wss://xxx.yyy.zzz.102:8006 ping=50ms timeout=1
</Proxy>
<Proxy balancer://wspve.xxxxxxxxxxxxxxx.xx>
BalancerMember ws://xxx.yyy.zzz.100:8006 ping=50ms timeout=1
BalancerMember ws://xxx.yyy.zzz.101:8006 ping=50ms timeout=1
BalancerMember ws://xxx.yyy.zzz.102:8006 ping=50ms timeout=1
</Proxy>
<VirtualHost *:80>
ServerName pve.xxxxxxxxxx.xx
ServerAdmin webmaster@xxxxxxxxxxxxxxx.xx
Redirect permanent / https://pve.xxxxxxxxxxxxxxx.xx/
</VirtualHost>
<VirtualHost *:443>
ServerName pve.xxxxxxxxxxxxxxx.xx
ServerAdmin webmaster@xxxxxxxxxxxxxxx.xx
SSLEngine on
SSLProtocol All -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCertificateFile /etc/apache2/ssl/pve-ssl.crt
SSLCertificateKeyFile /etc/apache2/ssl/pve-ssl.key
SSLProxyEngine on
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
ProxyRequests off
ProxyPreserveHost On
<Location />
ProxyPass balancer://pve.xxxxxxxxxxxxxxx.xx/
ProxyPassReverse balancer://pve.xxxxxxxxxxxxxxx.xx/
</Location>
<LocationMatch ^/(api2/json/nodes/[^\/]+/[^\/]+/[^\/]+/vncwebsocket.*)$>
ProxyPass balancer://wsspve.xxxxxxxxxxxxxxx.xx/$1
ProxyPassReverse balancer://wsspve.xxxxxxxxxxxxxxx.xx/$1
</LocationMatch>
<Location /websockify>
ProxyPass balancer://wspve.xxxxxxxxxxxxxxx.xx/
ProxyPassReverse balancer://wspve.xxxxxxxxxxxxxxx.xx/
</Location>
<LocationMatch ^/(api2/json/nodes/[^\/]+/vncwebsocket.*)$>
ProxyPass balancer://wsspve.xxxxxxxxxxxxxxx.xx/$1
ProxyPassReverse balancer://wsspve.xxxxxxxxxxxxxxx.xx/$1
</LocationMatch>
</VirtualHost>
Per prima cosa, definiamo 3 balancer, uno per le richieste HTTPS, uno per i WebSockets over HTTPS(wss://) ed uno per i WebSockets in chiaro.Questi balancer sono composti dai nostri nodi del cluster PVE.
Notiamo l’uso di ping a 50ms e di un timeout molto basso, in modo che se un server non risponde velocemente, si passi al successivo, in modo che l’utente non debba aspettare.
Successivamente vediamo un banale VirtualHost che risponde alle richieste sulla porta 80, forzando il redirect su HTTPS.
Il successivo VirtualHost, risponde alle richieste HTTPS, fornendo i certificati opportuni.
Subito dopo, diciamo ad Apache che non siamo in una situazione di “Forward”, ma di “Reverse” Proxy (ProxyRequest off) e che vogliamo venga preservato l’host originale nelle richieste inoltrate dal proxy.
L’ultima parte riguara le location. Nella prima, diciamo che tutte le richieste che vengono fatte all’indirizzo https://pve.xxxxxxxxxxxxxxx.xx/ vanno passate al balancer HTTPS.
La terza location è simile alla prima, ma indica che le richieste destinate a https://pve.xxxxxxxxxxxxxxx.xx/websockify, vanno dirottate verso il balancer che gestisce i WebSockets NON-HTTPS (ws://).
Infine, la seconda e la quarta location, usano una regexp per capire quale richiesta viene fatta e la dirottano verso il balancer per i WebSockets HTTPS (wss://).