Apache come proxy inverso su Ubuntu
Apache come proxy inverso è una scelta solida quando vuoi esporre un’app interna senza pubblicarla direttamente su Internet. Il web server riceve le richieste dall’esterno, applica regole di routing, TLS, header di sicurezza, compressione e logging, poi inoltra il traffico al servizio backend su porta locale, socket Unix o host remoto.
Su Ubuntu la configurazione è semplice, ma conviene impostarla bene fin dall’inizio: moduli corretti, VirtualHost puliti, gestione degli header, time-out coerenti con l’app e verifiche rapide per capire dove si rompe il flusso. Qui si lavora con Apache 2.4 su Ubuntu recente, ma la logica resta la stessa anche su versioni vicine.
Quando ha senso usare Apache come reverse proxy
Il proxy inverso è utile se vuoi:
- pubblicare più applicazioni dietro un solo IP e un solo certificato TLS;
- separare il livello web dal livello applicativo;
- aggiungere autenticazione, rate limit, header o redirect centralizzati;
- terminare TLS su Apache e parlare in HTTP verso servizi interni;
- mettere davanti applicazioni che ascoltano solo su localhost o su una rete privata.
È una soluzione tipica per app Node.js, Python, Go, Java, PHP-FPM dietro backend applicativi, dashboard interne, pannelli e servizi containerizzati. Se hai già un bilanciatore esterno o un CDN, Apache può stare dietro a quello oppure essere il punto di ingresso finale.
Architettura minima
Lo schema base è questo:
Client -> Apache su Ubuntu -> backend app su 127.0.0.1:porta oppure host internoApache può inoltrare richieste HTTP, WebSocket e in alcuni casi anche bilanciare tra più backend. Per la maggior parte delle installazioni bastano i moduli proxy standard e un VirtualHost dedicato per ogni sito.
Prerequisiti sul server Ubuntu
Prima di toccare Apache, verifica che il backend risponda localmente. Se il servizio non va già da solo, il proxy non lo risolve.
Controlli utili:
sudo systemctl status apache2curl -I http://127.0.0.1:3000Se il backend è su un altro host, prova prima la raggiungibilità di rete e la porta:
nc -vz 10.0.0.20 3000Se usi HTTPS verso il backend, verifica anche il certificato e il nome host, soprattutto se il backend presenta un certificato valido solo per un dominio preciso.
Abilitare i moduli necessari
Su Ubuntu Apache usa il sistema dei moduli abilitabili. Per un reverse proxy classico servono almeno proxy e proxy_http. Se devi gestire WebSocket, spesso serve anche proxy_wstunnel. Per header e rewrite possono servire altri moduli, ma non vanno attivati a caso.
sudo a2enmod proxy proxy_http headers rewrite sslSe l’app usa WebSocket:
sudo a2enmod proxy_wstunnelRicarica Apache dopo l’abilitazione dei moduli:
sudo apache2ctl configtest && sudo systemctl reload apache2Il test di sintassi deve restituire Syntax OK. Se fallisce, correggi prima di ricaricare.
VirtualHost base per reverse proxy
Il modo più pulito è creare un VirtualHost dedicato, ad esempio in /etc/apache2/sites-available/app.example.com.conf. Un esempio minimo con backend locale su porta 3000:
<VirtualHost *:80>
ServerName app.example.com
ProxyPreserveHost On
ProxyRequests Off
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
ErrorLog ${APACHE_LOG_DIR}/app_error.log
CustomLog ${APACHE_LOG_DIR}/app_access.log combined
</VirtualHost>La coppia ProxyPass e ProxyPassReverse è il cuore della configurazione. La prima inoltra il traffico, la seconda riscrive gli header di redirect del backend in modo che il client resti coerente sul dominio pubblico.
ProxyPreserveHost On conserva l’host originale richiesto dal client. È spesso la scelta giusta per app che fanno routing in base all’host o che generano URL assoluti. Se il backend si aspetta invece un host interno, puoi lasciarlo su Off, ma va deciso consapevolmente.
Abilitare il sito e fare il primo test
Dopo aver creato il file del VirtualHost:
sudo a2ensite app.example.com.confsudo apache2ctl configtestsudo systemctl reload apache2Verifica dall’esterno con:
curl -I http://app.example.comAtteso: risposta 200, 301 o 302 coerente con la tua app. Se vedi 502, 503 o 504, il problema è quasi sempre nel backend, nel routing o nei time-out. Se vedi la pagina di default di Apache, probabilmente il VirtualHost non è stato agganciato come previsto.
Reverse proxy con HTTPS
In produzione quasi sempre conviene terminare TLS su Apache. In questo modo il traffico tra client e front-end è cifrato, mentre il tratto verso il backend può restare interno e più semplice da gestire.
Un VirtualHost HTTPS tipico:
<VirtualHost *:443>
ServerName app.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/app.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/app.example.com/privkey.pem
ProxyPreserveHost On
ProxyRequests Off
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
ErrorLog ${APACHE_LOG_DIR}/app_ssl_error.log
CustomLog ${APACHE_LOG_DIR}/app_ssl_access.log combined
</VirtualHost>Molte applicazioni devono sapere che il client arriva via HTTPS, altrimenti generano redirect errati o cookie non sicuri. Per questo gli header X-Forwarded-Proto e X-Forwarded-Port sono importanti.
Se usi Let’s Encrypt con certbot, la gestione del certificato può essere automatizzata. In quel caso verifica che il rinnovo non rompa il VirtualHost e che Apache ricarichi correttamente la nuova chiave.
Gestione degli header forwardati
Dietro un proxy, il backend non vede più direttamente il client. Per questo conviene passare gli header standard in modo esplicito:
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
RequestHeader set X-Forwarded-Host "%{Host}e" env=HostApache spesso aggiunge già alcuni header di suo, ma non dare per scontato che bastino per tutte le applicazioni. Alcuni framework si aspettano anche X-Forwarded-For, che rappresenta l’IP del client originale. Apache lo gestisce normalmente, ma va verificato lato applicazione se il trust del proxy è configurato correttamente.
Se l’app genera redirect assoluti verso l’host interno, controlla:
ProxyPreserveHost;- config dell’app per “base URL” o “trusted proxies”;
- eventuali rewrite nel backend;
- header
X-Forwarded-ProtoeX-Forwarded-Host.
WebSocket e connessioni persistenti
Per applicazioni in tempo reale, dashboard live o chat, il reverse proxy deve supportare WebSocket. In Apache questo richiede in genere proxy_wstunnel e una regola dedicata.
<VirtualHost *:443>
ServerName ws.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/ws.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/ws.example.com/privkey.pem
ProxyPreserveHost On
ProxyRequests Off
ProxyPass "/socket" "ws://127.0.0.1:3000/socket"
ProxyPassReverse "/socket" "ws://127.0.0.1:3000/socket"
ProxyPass "/" "http://127.0.0.1:3000/"
ProxyPassReverse "/" "http://127.0.0.1:3000/"
</VirtualHost>Ordine e specificità contano. Le regole più specifiche devono stare prima di quelle generiche, altrimenti il traffico WebSocket finisce nella regola HTTP standard e la connessione si rompe.
Timeout, limiti e comportamento sotto carico
Un proxy inverso non deve tagliare richieste lente senza motivo, ma nemmeno tenere appese connessioni troppo a lungo. I timeout vanno allineati al comportamento reale del backend.
Parametri spesso utili:
ProxyTimeoutper il tempo massimo di attesa verso il backend;Timeoutglobale di Apache;- eventuali limiti del backend su request body e keep-alive;
- dimensione massima di upload se l’app gestisce file grandi.
Esempio:
<VirtualHost *:443>
ServerName app.example.com
ProxyTimeout 60
</VirtualHost>Se vedi 504 Gateway Timeout, non aumentare i timeout a caso. Prima misura la latenza reale del backend e capisci se il problema è codice, database, disco o saturazione CPU.
Proxy verso backend su host remoto
Il backend non deve per forza stare sulla stessa macchina. Puoi puntare a un host interno, per esempio un nodo applicativo in rete privata:
ProxyPass / http://10.0.0.20:8080/
ProxyPassReverse / http://10.0.0.20:8080/In questo scenario conviene:
- limitare l’esposizione del backend solo alla rete interna;
- bloccare l’accesso diretto dall’esterno con firewall o security group;
- verificare la risoluzione DNS se usi un nome host anziché un IP;
- allineare i certificati se il backend usa HTTPS.
Se il backend remoto è instabile, il proxy può diventare un punto di concentrazione del problema. Per questo sono utili log separati e metriche sulla latenza upstream.
Logging e diagnostica
Per capire rapidamente dove si rompe il flusso, tieni separati i log del VirtualHost. È molto più comodo che scavare nel log globale di Apache.
Controlli utili:
sudo tail -f /var/log/apache2/app_error.logsudo tail -f /var/log/apache2/app_access.logSe il backend risponde ma il client vede errore, cerca messaggi come:
AH01114: HTTP: failed to make connection to backendAH00898: Error reading from remote serverproxy: error reading status line from remote server
Questi indizi distinguono tra problema di connettività, backend morto, risposta malformata o timeout. Se non hai log dettagliati, abilita temporaneamente un livello più verboso solo sul VirtualHost interessato, poi riportalo alla normalità.
Hardening minimo del proxy
Un reverse proxy esposto su Internet va trattato come superficie critica. Alcune misure minime hanno un buon rapporto costo/beneficio:
- ProxyRequests Off per evitare di trasformare Apache in un open proxy;
- solo i moduli necessari, niente extra inutili;
- backend vincolato a localhost o rete privata;
- TLS moderno e certificati validi;
- header di sicurezza coerenti con l’app;
- permessi stretti sui file di configurazione e sulle chiavi private.
Se il proxy termina TLS, assicurati che le chiavi private siano leggibili solo da root o dall’utente previsto dal sistema, e che non finiscano in backup non protetti.
Bilanciamento semplice tra più backend
Apache può anche distribuire richieste su più backend. Per casi semplici, puoi definire un bilanciamento base con mod_proxy_balancer. È utile quando hai più istanze della stessa app e vuoi una disponibilità un po’ migliore o una distribuzione del carico elementare.
Un esempio concettuale:
<Proxy "balancer://appcluster">
BalancerMember http://10.0.0.21:8080
BalancerMember http://10.0.0.22:8080
</Proxy>
ProxyPass / balancer://appcluster/
ProxyPassReverse / balancer://appcluster/Qui conviene verificare bene la persistenza di sessione se l’app non è stateless. Se l’autenticazione dipende da cookie di sessione locali, il bilanciamento senza sticky session può creare logout casuali o errori intermittenti.
Troubleshooting rapido
Quando qualcosa non va, la sequenza utile è sempre la stessa: verifica DNS, poi Apache, poi backend, poi rete interna, poi applicazione. Non partire dal codice se non hai ancora confermato che il backend risponda.
Test minimi:
curl -I https://app.example.comcurl -I http://127.0.0.1:3000sudo apache2ctl configtestSe la risposta pubblica è 502 ma il backend locale risponde, guarda la configurazione del VirtualHost, il path di ProxyPass, la reachability verso l’host remoto e i log di Apache. Se il backend non risponde neppure localmente, il problema non è Apache.
Se vedi contenuti misti, redirect errati o loop infiniti, controlla i redirect nel backend e la coerenza tra HTTP e HTTPS. Molti errori nascono da una mancata comprensione del fatto che il backend “vede” una richiesta diversa da quella ricevuta dal client.
Esempio completo pronto da adattare
Questo esempio mostra un VirtualHost HTTPS con proxy verso un backend locale, header base e log separati:
<VirtualHost *:443>
ServerName app.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/app.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/app.example.com/privkey.pem
ProxyRequests Off
ProxyPreserveHost On
ProxyTimeout 60
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
ErrorLog ${APACHE_LOG_DIR}/app_error.log
CustomLog ${APACHE_LOG_DIR}/app_access.log combined
</VirtualHost>Dopo averlo inserito, fai sempre questa sequenza:
sudo apache2ctl configtestsudo systemctl reload apache2curl -I https://app.example.com- controllo log su
/var/log/apache2/app_error.log
Se serve un percorso specifico per API o WebSocket, aggiungilo con regole più precise prima della regola generica. Se devi fare manutenzione, puoi anche usare temporaneamente una pagina di fallback o un backend alternativo, ma va gestito con attenzione per non introdurre incoerenze.
Checklist operativa finale
- moduli corretti abilitati;
- VirtualHost dedicato e non ambiguo;
ProxyRequests Off;ProxyPasseProxyPassReversecoerenti;- header forwarded allineati all’app;
- backend raggiungibile prima di mettere in produzione;
- log separati per diagnosi rapida;
- test con
curlprima e dopo il reload; - certificati e rinnovi verificati se usi HTTPS.
Con questa base, Apache su Ubuntu funziona bene come reverse proxy per la maggior parte degli scenari classici: siti dinamici, API, pannelli interni e servizi applicativi dietro un front-end unico.
Commenti (0)
Nessun commento ancora.
Segnala contenuto
Elimina commento
Eliminare definitivamente questo commento?
L'azione non si può annullare.