My senior told me, that the caret-only match (e.g. the RewriteRule ^
part) does not work in .htaccess
, apparently only in virtualhost
That is nonsense. The ^
(regex syntax) simply asserts the start-of-string. Nothing more. So, if an argument takes a regex (regardless of context) the ^
is always going to "work", depending on what you are trying to match. (I'm wondering whether you really mean the slash prefix on the URL-path?)
apparently only in virtualhost
You could argue the opposite is true. ^$
will match in .htaccess
, but not in a virtualhost context. (This matches the root directory / homepage in a .htaccess
context.)
This is simply due to what is matched in these different contexts. (There are 4 contexts in the Apache config: .htaccess
, directory, virtualhost and server.)
In a virtualhost context, the RewriteRule
pattern matches against the full root-relative URL-path, starting with a slash. So, instead of ^$
, you would need to match ^/$
instead (to match the root directory).
Whereas in .htaccess
(and directory) context, the URL-path that is matched is relative to the directory that contains the .htaccess
file (the directory-prefix has been removed) and consequently does not start with a slash.
For example, given the URL https://example.com/foo/bar/baz
...
In a virtualhost context, the RewriteRule
pattern matches against the URL-path /foo/bar/baz
(the full URL-path starting with a slash.)
In .htaccess
in the root directory then the RewriteRule
pattern matches against foo/bar/baz
(no slash prefix). But if the .htaccess
file is located in the /foo
subdirectory (not the root) then the URL-path that is matched is: bar/baz
only (/foo
is omitted).
Apparently, the correct rule would be RewriteRule ^(.*) https://sub.another.com/$1 [R=301,L]
. Can anyone please explain why the match doesn't work in .htaccess
?
This does work in .htaccess
. In fact, this would only work properly in .htaccess
, since if you used this rule in a virtualhost context then you would end up with a double-slash at the start of the URL-path in the redirected request. (Of course, other rules can affect this behaviour and the location of the .htaccess
file - if in a subdirectory - will change this behaviour also.)
If the internet is to be believed, both ^
and ^(.*)
should match the entire line.
^
by itself does not match anything, it simply asserts the start-of-string, so is always "successful". Whereas ^(.*)
asserts the start-of-string and then matches the rest of the URL-path and captures this in a backreference. In fact, the ^
prefix in ^(.*)
is entirely optional (when matching URL-paths) since the regex is greedy. ^(.*)
and (.*)
are "the same".
Since you are using a $1
backreference in the substitution string you need to actually capture something, so you need (.*)
(since ^
does not match/capture anything, it's simply an assertion). But this is the same, regardless of where you are using this directive: .htaccess
or virtualhost.
In this particular rule, you could use ^
only and use the REQUEST_URI
server variable in the substitution string instead. For example:
RewriteRule ^ https://sub.another.com%{REQUEST_URI} [R=301,L]
Note that the REQUEST_URI
variable contains the entire URL-path, including the slash prefix, so the slash is omitted in the substitution string. This rule is arguably "better" than using the backreference (your rule above) since it works anywhere (any directory), regardless of context and uses a more efficient regex.