Context
With the following rule:
# Redirect root url to /tvs
RewriteRule ^/$ /tvs [R=301,L]
I have an absolute redirection like:
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Fri, 24 Mar 2017 16:42:23 GMT
Content-Type: text/html; charset=iso-8859-1
Content-Length: 312
Location: http://www.tvsvizzera.it/tvs
Vary: Accept-Encoding
X-Node: pcache02
X-Cached: MISS
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
and in the rewrite.log I have the following
10.101.114.1 - - [24/Mar/2017:16:43:34 +0100] [www.tvsvizzera.it/sid#7fd446c22168][rid#7fd446d6eb48/initial] (2) init rewrite engine with requested uri /
10.101.114.1 - - [24/Mar/2017:16:43:34 +0100] [www.tvsvizzera.it/sid#7fd446c22168][rid#7fd446d6eb48/initial] (2) rewrite '/' -> '/tvs'
10.101.114.1 - - [24/Mar/2017:16:43:34 +0100] [www.tvsvizzera.it/sid#7fd446c22168][rid#7fd446d6eb48/initial] (2) explicitly forcing redirect with http://www.tvsvizzera.it/
tvs
10.101.114.1 - - [24/Mar/2017:16:43:34 +0100] [www.tvsvizzera.it/sid#7fd446c22168][rid#7fd446d6eb48/initial] (1) escaping http://www.tvsvizzera.it/tvs for redirect
10.101.114.1 - - [24/Mar/2017:16:43:34 +0100] [www.tvsvizzera.it/sid#7fd446c22168][rid#7fd446d6eb48/initial] (1) redirect to http://www.tvsvizzera.it/tvs [REDIRECT/301]
Why does apache explicitly force the redirect to be absolute ?
Problem
The server is behind a reverse proxy doing the SSL Offloading.
So if the redirection would stay relative the same rule would work for both protocol HTTP/HTTPS. But this isn't the case and when requesting with https, one gets redirected to http.
I know I can change the rule to be something like this
RewriteRule ^/$ %{ENV:REQUEST_SCHEME}://%{HTTP_HOST}/tvs [R=permanent,L]
But I wanted to understand this behavior.
Thanks for any explanation.
Best Answer
All external redirects (
R
flag) result in mod_rewrite requiring an absolute URL. When you don't explicitly include the scheme and hostname in theRewriteRule
substitution then Apache will use the current protocol, server name and port. Apache (or strictly speaking, mod_rewrite) doesn't send a relative URL back in theLocation:
HTTP response header hoping that the user-agent will resolve the URL.(It was not until June 2014 (RFC 7231) that relative URLs in the
Location:
header officially became part of the standard. So, particularly if you're still on Apache 2.2, then it's difficult to argue that Apache is doing anything wrong here.)If Apache is sending back an HTTP URL (as opposed to HTTPS) then it would seem that Apache is serving the response back over HTTP, not HTTPS.
Yes, you could manually "fix" the URL using mod_rewrite. However, the
REQUEST_SCHEME
server variable is likely to have the same "problem". If you are behind a proxy then you might need to check theX-Forwarded-Proto
header (or similar) as to whether it's "http" or "https".As well as (conditionally) forcing HTTPS in the directive itself, you can also force HTTPS in the server config with the
ServerName
(andUseCanonicalName
) directive(s). However, I assume that is not desirable and you need to be flexible?You can also edit the
Location:
header, before it is sent back to the client. Using mod_headers you can force a relative URL by manually stripping out the scheme + hostname, as suggested in this StackOverflow answer:Further reference: