Setup Apache2 SSL as a Reverse Proxy

apache-2.2reverse-proxy

I have a web application that handles potentially sensitive information that needs to be exposed more publicly. Unfortunately it has it's own proprietary webserver built in that doesn't support SSL. Due too a software approval process I have to use Apache as the reverse proxy.

I have it almost entirely working, directly accessing any page on over SSL works perfectly but redirects sent by the webserver are not being rewritten. For example attempting to access the root URL https://frontend.example.tld:4000/ when you are not logged in should redirect you to https://frontend.example.tld:4000/login but instead it's redirecting to http://frontend.example.tld:4000/login which results in a BadRequest.

All of the Googling I've done on this have revealed outdated settings that don't seem to be available in apache2 anymore are are suggesting changing the application behind the proxy to handle it (which unfortunately isn't an option).

Here is the relevant portion of my apache config:

<IfModule mod_ssl.c>
  Listen 4000

  <VirtualHost *:4000>
    ServerAdmin webmaster@localhost
    ServerName frontend.example.tld

    CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined
    CustomLog ${APACHE_LOG_DIR}/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
    ErrorLog ${APACHE_LOG_DIR}/error.log
    LogLevel info

    SSLProtocol -ALL +SSLv3 +TLSv1
    SSLCipherSuite ALL:!ADH:!EXPORT56:!EXP:!eNULL:!aNULL:RC4+RSA:+HIGH:+MEDIUM:!LOW:!SSLv2

    SSLEngine on
    SSLCertificateFile    /etc/ssl/certs/frontend.crt
    SSLCertificateKeyFile /etc/ssl/private/frontend.key
    SSLCertificateChainFile  /etc/ssl/certs/gd_bundle.crt

    BrowserMatch "MSIE [2-6]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
    BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown

    ProxyRequests Off
    ProxyPreserveHost On

    ProxyPass / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/
  </VirtualHost>
</IfModule> 

Elsewhere I have the proxy and proxy_http module loaded.

Update:

Here are the contents of the error message received after the attempted redirect:

Bad Request

Your browser sent a request that this server could not understand.
Reason: You're speaking plain HTTP to an SSL-enabled server port.
Instead use the HTTPS scheme to access this URL, please. Hint:
https://frontend.example.tld/

Best Answer

Seems like the application is generating that Location header based on the contents of the incoming Host header, which is kinda what we wanted (and made possible by ProxyPreserveHost), but it doesn't know the correct protocol for the new location.

Based on the way the application seems to be working, we have a couple options for dealing with this:

  1. Turn ProxyPreserveHost Off and see if that helps; the generated Location header should then match your existing ProxyPassReverse and be modified accordingly to the correct URL, or if that doesn't work;
  2. Add a new ProxyPassReverse line (leaving the old one in place as well) attempting to match and alter the Location headers that the application is sending.

    ProxyPassReverse / http://frontend.example.tld:4000/