Apache con Mod Proxy e Remote IP (Home Assistant incluso)

Apache con Mod Proxy e Remote IP (Home Assistant incluso)

Buongiorno a tutti.

Oggi vi vorrei parlare dell’utilizzo di Apache come proxy.
Una delle principali utilità di questa funzione è quella di tenere isolati in una rete privata e protetta da firewall i server importanti e utilizzare una sola macchina esposta a internet per incanalare su di essa tutti gli accessi.

In un contesto anche casalingo ipotizziamo di avere una macchina linux che esporta verso l’esterno le porte 80 e 443. Ipotizziamo inoltre di avere nella nostra rete anche altri oggetti come ad esempio Home Assistant (in esecuzione sulla medesima macchina ma su porta differente) e magari anche un NAS che vogliamo controllare da remoto.
Ricordo che per sicurezza è sempre meglio usare VPN per accedere a server con contenuti sensibili.

Vediamo ora come procedere per far si che collegandosi da remoto alla macchina esposta ad internet questa si colleghi a sua volta ai server web interni e recuperi per noi le informazioni richieste.
Premessa: per permettere questa funzionalità è necessario avere diversi nomi dns che puntino all’ip esposto. Nella guida ipotizzo:
-> host1.domain1
-> host2.domain1
-> host3.domain1
Ove domain1 può tranquillamente essere un indirizzo dinamico offerto dai più noti servizi di dynamic dns. host1 sarà la macchina linux su cui è in esecuzione apache2 e lavorerà da proxy, mentre host2 e host3 saranno servizi interni alla rete (e.g. host2 sarà Home Assistant e host3 sarà il NAS).

A questo considerando di avere una distribuzione linux debian con apache2 installato (l’installazione e la configurazione di base di apache2 non rientra nell’oggetto della guida) procediamo ad abilitare i moduli necessari:

# a2enmod proxy
# a2enmod proxy_html
# a2enmod proxy_http
# a2enmod proxy_wstunnel
# a2enmod remoteip

I moduli proxy, proxy_html e proxy_wstunnel servono per consentire gestire le richieste verso altri server web, il modulo remoteip servirà per consentire agli altri server di identificare l’IP reale di origine della richiesta. Senza quest’ultimo nei log dei server interni verrà sempre visualizzato come IP sorgente l’IP della macchina usata come proxy nella rete locale.

A questo punto occorrerà creare dei virtual host, ciascuno dei quali corrispondente alla macchina interna da rendere visibile all’esterno. Vediamo di seguito un esempio molto semplice di host virtuale con proxy verso ad esempio il NAS (host3):

<VirtualHost *:80>
ServerName <host3.domain1>
ServerAdmin <EMAIL>

ProxyPass / http://INTERNAL_IP:INTERNAL_PORT/
ProxyPassReverse / http://INTERNAL_IP:INTERNAL_PORT/

# Available loglevels: trace8, …, trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with “a2disconf”.
#Include conf-available/serve-cgi-bin.conf
</VirtualHost>

Qualsiasi richiesta di connessione dall’esterno all’host host3.domain verrà rediretta dal server proxy di apache2 verso l’indirizzo http://INTERNAL_IP:INTERNAL_PORT.

Di seguito riporto un esempio ben specifico relativo a Home Assistant in esecuzione sulla stessa macchina locale dove le richieste esterne verso di essa sono ridirezionate per utilizzare SSL (la configurazione di SSL per apache2 non è oggetto di questa guida).

<VirtualHost *:80>
ServerName <host2.domain1>
ServerAdmin <EMAIL>
#RedirectMatch ^(.*) https://<host1.domain1>
RewriteEngine on
RewriteCond %{HTTPS} !=on
RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [NE,R,L]
</VirtualHost>

<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName <host2.domain1>
ServerAdmin <EMAIL>

ProxyPreserveHost On
ProxyRequests off
ProxyPass /api/websocket ws://localhost:8123/api/websocket
ProxyPassReverse /api/websocket ws://localhost:8123/api/websocket
ProxyPass / http://localhost:8123/
ProxyPassReverse / http://localhost:8123/

RewriteEngine on
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:8123/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://localhost:8123/$1 [P,L]

# Available loglevels: trace8, …, trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with “a2disconf”.
#Include conf-available/serve-cgi-bin.conf
</VirtualHost>
</IfModule>

Qualsiasi richiesta di connessione dall’esterno verso l’indirizzo http://host2.domain1 verrà automaticamente rediretta verso https://host2.domain1. Home Assistant sarà in esecuzione localmente (senza SSL).

I file di configurazione dei virtual host di apache2 dovranno essere salvati in /etc/apache2/sites-available e dovranno avere un nome col seguente formato: nome_host.conf.

Per abilitare i siti occorrerà eseguire il comando:

# a2ensite nome_host

Fatto ciò basta riavviare apache2 ed il gioco è fatto:

# /etc/init.d/apache2 restart

Ultima nota relativamente all’indirizzo IP sorgente della richiesta. Affinché funzioni correttamente il modulo remoteip richiede che nel webserver di destinazione della richiesta (e.g. host2 e host3) sia configurato aggiungendo quanto segue:

RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy <IP_PROXY_APACHE>

si può inserire questa configurazione in un file dedicato ad esempio in /etc/apache2/conf.d/remoteip.conf e abilitandola con

# a2enconf remoteip

Ultima cosa da fare è modificare la gestione dei log nel file /etc/apache2/apache2.conf: identificando le righe:

LogFormat “%h %l %u %t \”%r\” %>s %O \”%{Referer}i\” \”%{User-Agent}i\”” combined
LogFormat “%h %l %u %t \”%r\” %>s %O” common

e sistituendo a %h %a ottenendo quindi:

LogFormat “%a %l %u %t \”%r\” %>s %O \”%{Referer}i\” \”%{User-Agent}i\”” combined
LogFormat “%a %l %u %t \”%r\” %>s %O” common

Per completezza allego la configurazione di home assistant per riconoscere gli IP esterni. Nel file configuration.yaml occorre aggiungere nella parte http le seguenti stringhe:

http:
use_x_forwarded_for: true
trusted_proxies: 127.0.0.1
trusted_networks:
– NET1
– NET2

Ove NET1 e NET2 sono due ipotetiche reti locali.

Alla prossima!

Share this content: