mod rewrite – How does RewriteBase work in .htaccess
mod rewrite – How does RewriteBase work in .htaccess
In my own words, after reading the docs and experimenting:
You can use RewriteBase
to provide a base for your rewrites. Consider this
# invoke rewrite engine
RewriteEngine On
RewriteBase /~new/
# add trailing slash if missing
rewriteRule ^(([a-z0-9-]+/)*[a-z0-9-]+)$ $1/ [NC,R=301,L]
This is a real rule I used to ensure that URLs have a trailing slash. This will convert
http://www.example.com/~new/page
to
http://www.example.com/~new/page/
By having the RewriteBase
there, you make the relative path come off the RewriteBase
parameter.
RewriteBase
is only applied to the target of a relative rewrite rule.
-
Using RewriteBase like this…
RewriteBase /folder/ RewriteRule a.html b.html
-
is essentially the same as…
RewriteRule a.html /folder/b.html
-
But when the .htaccess file is inside
/folder/
then this also points to the same target:RewriteRule a.html b.html
Although the docs imply always using a RewriteBase
, Apache usually detects it correctly for paths under the DocumentRoot unless:
-
You are using
Alias
directives -
You are using .htaccess rewrite rules to perform HTTP redirects (rather than just silent rewriting) to relative URLs
In these cases, you may find that you need to specify the RewriteBase.
However, since its a confusing directive, its generally better to simply specify absolute (aka root relative) URIs in your rewrite targets. Other developers reading your rules will grasp these more easily.
Quoting from Jon Lins excellent in-depth answer here:
In an htaccess file, mod_rewrite works similar to a <Directory>
or <Location>
container. and the RewriteBase
is used to provide a relative path base.
For example, say you have this folder structure:
DocumentRoot
|-- subdir1
`-- subdir2
`-- subsubdir
So you can access:
http://example.com/
(root)http://example.com/subdir1
(subdir1)http://example.com/subdir2
(subdir2)http://example.com/subdir2/subsubdir
(subsubdir)
The URI that gets sent through a RewriteRule
is relative to the directory containing the htaccess file. So if you have:
RewriteRule ^(.*)$ -
- In the root htaccess, and the request is
/a/b/c/d
, then the captured URI ($1
) isa/b/c/d
. - If the rule is in
subdir2
and the request is/subdir2/e/f/g
then the captured URI ise/f/g
. - If the rule is in the
subsubdir
, and the request is/subdir2/subsubdir/x/y/z
, then the captured URI isx/y/z
.
The directory that the rule is in has that part stripped off of the URI. The rewrite base has no affect on this, this is simply how per-directory works.
What the rewrite base does do, is provide a URL-path base (not a file-path base) for any relative paths in the rules target. So say you have this rule:
RewriteRule ^foo$ bar.php [L]
The bar.php
is a relative path, as opposed to:
RewriteRule ^foo$ /bar.php [L]
where the /bar.php
is an absolute path. The absolute path will always be the root (in the directory structure above). That means that regardless of whether the rule is in the root, subdir1, subsubdir, etc. the /bar.php
path always maps to http://example.com/bar.php
.
But the other rule, with the relative path, its based on the directory that the rule is in. So if
RewriteRule ^foo$ bar.php [L]
is in the root and you go to http://example.com/foo
, you get served http://example.com/bar.php
. But if that rule is in the subdir1 directory, and you go to http://example.com/subdir1/foo
, you get served http://example.com/subdir1/bar.php
. etc. This sometimes works and sometimes doesnt, as the documentation says, its supposed to be required for relative paths, but most of the time it seems to work. Except when you are redirecting (using the R
flag, or implicitly because you have http://host
in your rules target). That means this rule:
RewriteRule ^foo$ bar.php [L,R]
if its in the subdir2 directory, and you go to http://example.com/subdir2/foo
, mod_rewrite will mistake the relative path as a file-path instead of a URL-path and because of the R
flag, youll end up getting redirected to something like: http://example.com/var/www/localhost/htdocs/subdir1
. Which is obviously not what you want.
This is where RewriteBase
comes in. The directive tells mod_rewrite what to append to the beginning of every relative path. So if I have:
RewriteBase /blah/
RewriteRule ^foo$ bar.php [L]
in subsubdir, going to http://example.com/subdir2/subsubdir/foo
will actually serve me http://example.com/blah/bar.php
. The bar.php is added to the end of the base. In practice, this example is usually not what you want, because you cant have multiple bases in the same directory container or htaccess file.
In most cases, its used like this:
RewriteBase /subdir1/
RewriteRule ^foo$ bar.php [L]
where those rules would be in the subdir1 directory and
RewriteBase /subdir2/subsubdir/
RewriteRule ^foo$ bar.php [L]
would be in the subsubdir directory.
This partly allows you to make your rules portable, so you can drop them in any directory and only need to change the base instead of a bunch of rules. For example if you had:
RewriteEngine On
RewriteRule ^foo$ /subdir1/bar.php [L]
RewriteRule ^blah1$ /subdir1/blah.php?id=1 [L]
RewriteRule ^blah2$ /subdir1/blah2.php [L]
...
such that going to http://example.com/subdir1/foo
will serve http://example.com/subdir1/bar.php
etc. And say you decided to move all of those files and rules to the subsubdir directory. Instead of changing every instance of /subdir1/
to /subdir2/subsubdir/
, you could have just had a base:
RewriteEngine On
RewriteBase /subdir1/
RewriteRule ^foo$ bar.php [L]
RewriteRule ^blah1$ blah.php?id=1 [L]
RewriteRule ^blah2$ blah2.php [L]
...
And then when you needed to move those files and the rules to another directory, just change the base:
RewriteBase /subdir2/subsubdir/
and thats it.
mod rewrite – How does RewriteBase work in .htaccess
AFAIK, RewriteBase is only used to fix cases where mod_rewrite is running in a .htaccess
file not at the root of a site and it guesses the wrong web path (as opposed to filesystem path) for the folder it is running in. So if you have a RewriteRule in a .htaccess in a folder that maps to http://example.com/myfolder
you can use:
RewriteBase myfolder
If mod_rewrite isnt working correctly.
Trying to use it to achieve something unusual, rather than to fix this problem sounds like a recipe to getting very confused.