He estado trabajando en un proxy inverso local que enruta el tráfico entre dos instalaciones locales de Apache (cada una con una versión diferente de mod_wsgi, que es el motivo de la bifurcación). Quiero que este proxy inverso funcione ya sea que las solicitudes sean HTTP o HTTPS.
Sin embargo, cuando se usa SSL, ProxyPassReverse no modifica (correctamente) el encabezado de respuesta de la ubicación.
A continuación se encuentran las definiciones de VirtualHost para el tráfico HTTP y HTTPS, respectivamente:
<VirtualHost *:80> # Proxy traffic for Version 6 with an alias of: 6x/ ProxyPass /6x/ http://localhost:10090/ ProxyPassReverse /6x/ http://localhost:10090/ # Proxy traffic for previous versions with aliases of: 5x/, 4x/, and / ProxyPass /5x/ http://localhost:10080/ ProxyPassReverse /5x/ http://localhost:10080/ ProxyPass /4x/ http://localhost:10080/ ProxyPassReverse /4x/ http://localhost:10080/ ProxyPass / http://localhost:10080/ ProxyPassReverse / http://localhost:10080/ </VirtualHost> <IfModule mod_ssl.c> <VirtualHost *:443> ServerName snakeoil.us.com ProxyPreserveHost on ProxyRequests off SSLEngine on SSLProxyEngine on SSLProxyVerify none SSLProxyCheckPeerCN off SSLProxyCheckPeerName off SSLProxyCheckPeerExpire off SSLCertificateFile /etc/ssl/certs/snakeoil.crt SSLCertificateKeyFile /etc/ssl/certs/snakeoil.key SSLCertificateChainFile /etc/ssl/certs/bundle-client.crt # Proxy traffic for Version 6 with an alias of: 6x/ ProxyPass /6x/ https://localhost:10453/ ProxyPassReverse /6x/ https://localhost:10453/ # Proxy traffic for previous versions with aliases of: 5x/, 4x/, and / ProxyPass /5x/ https://localhost:10443/ ProxyPassReverse /5x/ https://localhost:10443/ ProxyPass /4x/ https://localhost:10443/ ProxyPassReverse /4x/ https://localhost:10443/ ProxyPass / https://localhost:10443/ ProxyPassReverse / https://localhost:10443/ </VirtualHost> </IfModule> Cuando accedo a la url http://snakeoil.us.com/6x/snk610/index , el encabezado de la ubicación regresa como: Location: http://snakeoil.us.com/6x/snk610/index .
Sin embargo, cuando accedo a la URL https://snakeoil.us.com/6x/snk610/index , el encabezado de la ubicación vuelve como: Location: https://snakeoil.us.com/snk610/index , lo que da como resultado un 404 ya que solo una de las dos instancias locales de Apache (la asociada con la ruta 6x) que se envía mediante proxy reconoce el alias snk610 (y no es la instancia a la que se enruta en este caso).
La conclusión es que la definición HTTP VirtualHost procesa las solicitudes entre las dos instancias locales de Apache sin fallar. Sin embargo, la definición HTTPS VirtualHost no lo hace y no me queda claro qué causa esta discrepancia.
Logró encontrar la solución. En retrospectiva, debería haber sido más obvio.
En las instancias de Apache a las que se envía proxy, cambié el formato de access_log para que sea el siguiente:
LogFormat "%h %l %u %t \"%r\" %>s %b --> ResponseLocation: '%{Location}o'" commonEsto hace que se registre la ubicación de la respuesta saliente.
Aquí está el resultado de la instancia HTTP de Apache (al que se le envía un proxy):
[snake6x@test1 httpd6x]$ grep "ResponseLocation: 'http" logs/access_log ::1 - - [06/May/2020:15:43:25 -0400] "GET /snk610 HTTP/1.1" 301 233 --> ResponseLocation: 'http://localhost:10090/snk610/index' ::1 - - [06/May/2020:15:43:30 -0400] "GET /snk610/index HTTP/1.1" 302 247 --> ResponseLocation: 'http://localhost:10090/snk610/login?params=&message=&redirect_to=index' ::1 - - [06/May/2020:15:43:32 -0400] "POST /snk610/auth?redirect_to=index¶ms= HTTP/1.1" 302 204 --> ResponseLocation: 'http://localhost:10090/snk610/index'De lo anterior, puede ver que el encabezado de la ubicación de respuesta se ve como se esperaba, es decir, ProxyPassReverse debería poder realizar su reemplazo con éxito.
Por el contrario, aquí está el resultado de la instancia de Apache HTTPS (al que se le envía un proxy):
[snake6x@test1 httpd]$ grep "ResponseLocation: 'http" logs/ssl_request_log [06/May/2020:19:53:38 +0000] ::1 "GET /snk610 HTTP/1.1" 240 2645788 --> ResponseLocation: 'https://snakeoil.us.com/snk610/index' [06/May/2020:19:56:21 +0000] ::1 "GET /snk610/index HTTP/1.1" 254 2682899 --> ResponseLocation: 'https://snakeoil.us.com/snk610/login?params=&message=&redirect_to=index' [06/May/2020:19:56:23 +0000] ::1 "POST /snk610/auth?redirect_to=index¶ms= HTTP/1.1" 240 752392 --> ResponseLocation: 'https://snakeoil.us.com/snk610/index'De lo anterior, puede ver que el nombre del servidor se ha sustituido por el nombre del host entrante en el encabezado de la ubicación de la respuesta. Esto es lo que estaba causando que ProxyPassReverse no pudiera reemplazar el nombre de host saliente (en el servidor proxy inverso).
Resolví este problema actualizando explícitamente el encabezado de ubicación saliente en el servidor al que se dirige:
# Since this server has a proxy immediately in front of it, we need the outgoing # location to match the incoming location. However, the ServerName tag will # cause the incoming location to be changed to include the ServerName, which will # cause the upstream ProxyPassReverse to fail to update the outgoing location # properly. # # This Header modification replaces the outgoing ServerName with the incoming # name. # # FIXME: There is surely a better way to do this with a variable that contains # the incoming host Header edit Location ^https://snakeoil.us.com:443 https://localhost:10453 Header edit Location ^https://snakeoil.us.com https://localhost:10453