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-Proto
header. (It also sets the newForwarded
header for future compatibility, but I will leave that out below for brevity.) - Everything I have read lately suggests to use
Redirect
orRedirectMatch
instead ofRewriteRule
. Accordingly, I would like to avoidRewriteRule
if 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
Alias
entries 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
Redirect
andRedirectMatch
are unable to make use of the%{HTTP_HOST}
server variable. This means I would need extra logic to have a differentRedirectMatch
line depending on the host that was use by the client (Messy). - In the event that I NEED to use
mod_rewrite
for this, it would be good to have theRewriteRule
inside 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?