问题
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?
回答1:
RedirectMatch
is only good for relatively indiscriminate redirects, which is why it meets the needs of most. Keep your crypto proxy clean and either add a header to the back-end request denoting the connection was encrypted (not sure how to do that), or connect to a different port, e.g. 8443
that you would add to the same Listen
or <VirtualHost>
that has the 8080
in the back-end. The back-end would still not use an encrypted connection but would know whether the the connection is "secure" by checking headers or port. These checks can be performed by the back-end – quite easily – in either RewriteCond
s via %{HTTP:X-Your-Https-Header}
or %{SERVER_PORT}
, or in the site's scripting language and have redirects sent from it, since only it knows which URLs require redirects. It can send out the redirect complete with https:
since that's what the client needs to request, and your back-end will get the new request proxied with the correct header/port.
Edit: example of configuration on crypto server
<LocationMatch "/backendcontextroot">
ProxyPreserveHost on
<If "%{HTTPS} == 'on'">
ProxyPass "http://192.168.0.2:8443/backendcontextroot"
<Else>
ProxyPass "http://192.168.0.2:8080/backendcontextroot"
</If>
</LocationMatch>
来源:https://stackoverflow.com/questions/40263713/redirecting-http-traffic-to-https-in-apache-without-using-mod-rewrite