I am trying a pretty simple thing that I would normally do using a RewriteRule (and which works perfectly when I do).
My goal:
Force certain (not all) URLs to use the https protocol.
Caveats:
- Apache is behind a crypto-offloader. We would like a single virtual host that deals with both the unencrypted and the decrypted traffic. The offloader forwards all traffic to the same port and sets the
X-Forwarded-Protoheader. (It also sets the newForwardedheader for future compatibility, but I will leave that out below for brevity.) - Everything I have read lately suggests to use
RedirectorRedirectMatchinstead ofRewriteRule. Accordingly, I would like to avoidRewriteRuleif possible. - The URLs I wish to force are reverse proxies that I have configured in a
<LocationMatch>section within my virtual host. - The virtual host has multiple
Aliasentries that all correspond to valid names that are included in the TLS certificate (i.e. I don't want/need to force users to use the canonical name) - It seems that
RedirectandRedirectMatchare unable to make use of the%{HTTP_HOST}server variable. This means I would need extra logic to have a differentRedirectMatchline depending on the host that was use by the client (Messy). - In the event that I NEED to use
mod_rewritefor this, it would be good to have theRewriteRuleinside the<LocationMatch>section to keep the configuration for that path/proxy in one place. However this also seems to cause problems.
Time for some example code to help explain this. All of the following examples reside within a VirtualHost section as follows:
<VirtualHost 192.168.0.1:80>
ServerName www.example.com
ServerAlias example.com
ServerAlias anothervalidalias.com
Option 1 - Using RedirectMatch. This works but forces the hostname.
<LocationMatch "/backendcontextroot">
ProxyPreserveHost on
ProxyPass "http://192.168.0.2:8080/backendcontextroot"
<If "-z req('X-Forwarded-Proto')">
RedirectMatch ^(.*) https://www.example.com/$1
</If>
</LocationMatch>
Option 2 - Using RedirectMatch. This would be my ideal solution, but the HTTP_HOST does not work. Apache sends no response back to the client.
<LocationMatch "/backendcontextroot">
ProxyPreserveHost on
ProxyPass "http://192.168.0.2:8080/backendcontextroot"
<If "-z req('X-Forwarded-Proto')">
RedirectMatch ^(.*) https://%{HTTP_HOST}/$1
</If>
</LocationMatch>
Option 3 - Using RewriteRule within a LocationMatch block. If I really cannot use Redirect and am forced to use RewriteRule then this would be my preferred method as it keeps the configuration for the /backendcontextroot reverse proxy together in one place. However, this produces some 'funky' redirects...
<LocationMatch "/backendcontextroot">
ProxyPreserveHost on
ProxyPass "http://192.168.0.2:8080/backendcontextroot"
RewriteEngine on
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1
</LocationMatch>
This redirects to: https://www.example.com/proxy:http://192.168.0.2:8080/backendcontextroot
Option 4 - Using RewriteRule outside the LocationMatch block. This works, but the configuration for this reverse proxy is then 'spread around'. It also uses RewriteRule despite suggestions that I should avoid it if possible.
RewriteEngine on
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{REQUEST_URI} ^/backendcontextroot
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1
<LocationMatch "/backendcontextroot">
ProxyPreserveHost on
ProxyPass "http://192.168.0.2:8080/backendcontextroot"
</LocationMatch>
Am I stuck using option 4 or is there a more elegant way?