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) is a/b/c/d.
  • If the rule is in subdir2 and the request is /subdir2/e/f/g then the captured URI is e/f/g.
  • If the rule is in the subsubdir, and the request is /subdir2/subsubdir/x/y/z, then the captured URI is x/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.

Leave a Reply

Your email address will not be published.