I have seen this in a few .htaccess examples
RewriteBase /
It appears to be somewhat similar in functionality to the <base href=""> of HTML.
I believe it may automatically prepend its value to the beginning of RewriteRule statements (possibly ones without a leading slash)?
I could not get it to work properly. I think it's use could come in very handy for site portability, as I often have a development server which is different to a production one. My current method leaves me deleting portions out of my RewriteRule statements.
Can anyone explain to me briefly how to implement it?
Thanks
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 it's a confusing directive, it's 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 Lin's 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 rule's 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, it's 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 doesn't, as the documentation says, it's 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 rule's target). That means this rule:
RewriteRule ^foo$ bar.php [L,R]
if it's 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, you'll 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 can't have multiple bases in the same directory container or htaccess file.
In most cases, it's 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 that's it.
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.
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 isn't working correctly.
Trying to use it to achieve something unusual, rather than to fix this problem sounds like a recipe to getting very confused.
RewriteBase is only useful in situations where you can only put a .htaccess at the root of your site. Otherwise, you may be better off placing your different .htaccess files in different directories of your site and completely omitting the RewriteBase directive.
Lately, for complex sites, I've been taking them out, because it makes deploying files from testing to live just one more step complicated.
When I develop, it's on a different domain within a folder. When I take a site live, that folder doesn't exist anymore. Using RewriteBase allows me to use the same .htaccess file in both environments.
When live:
RewriteBase /
# RewriteBase /dev_folder/
When developing:
# RewriteBase /
RewriteBase /dev_folder/
The clearest explanation I found was not in the current 2.4 apache docs, but in version 2.0.
# /abc/def/.htaccess -- per-dir config file for directory /abc/def
# Remember: /abc/def is the physical path of /xyz, i.e., the server
# has a 'Alias /xyz /abc/def' directive e.g.
RewriteEngine On
# let the server know that we were reached via /xyz and not
# via the physical path prefix /abc/def
RewriteBase /xyz
How does it work? For you apache hackers, this 2.0 doc goes on to give "detailed information about the internal processing steps."
Lesson learned: While we need to be familiar with "current," gems can be found in the annals.
This command can explicitly set the base URL for your rewrites. If you wish to start in the root of your domain, you would include the following line before your RewriteRule:
RewriteBase /
I believe this excerpt from the Apache documentation, complements well the previous answers :
This directive is required when you use a relative path in a
substitution in per-directory (htaccess) context unless either of the
following conditions are true:
The original request, and the substitution, are underneath the DocumentRoot (as opposed to reachable by other means, such as Alias).
The filesystem path to the directory containing the RewriteRule, suffixed by the relative substitution is also valid as a URL path on
the server (this is rare).
As previously mentioned, in other contexts, it is only useful to make
your rule shorter. Moreover, also as previously mentioned, you can
achieve the same thing by placing the htaccess file in the
subdirectory.
I simply delete .htaccess file and it runs perfectly
Related
Please could I have some help redirecting URLs to a subfolder so that everything in https://example.com is rewritten to https://example.co.uk/subfolder?
The .htaccess file needs to be in /subfolder.
You could do something like the following in the root .htaccess file to rewrite all direct requests to the subfolder.
RewriteEngine On
# Rewrite all direct requests to the `/subfolder` directory
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^ subfolder%{REQUEST_URI} [L]
The check against the REDIRECT_STATUS environment variable ensures that only direct requests from the client (as opposed to internally rewritten requests) are rewritten to the /subfolder directory (thus avoiding a rewrite loop).
This also means that a direct request for /subfolder itself will also be rewritten to the /subfolder directory (ie. /subfolder/subfolder) - so you can have a sub-subfolder of the same name if you wish (otherwise direct requests for /subfolder will result in a 404). That is, unless you have an additional .htaccess file in the subfolder that also contains mod_rewrite directives, in which case these directives will be overridden.
UPDATE: Following your question update that now states the following...
The .htaccess file needs to be in /subfolder.
In that case, this is not possible. The .htaccess file that rewrites requests to the /subfolder must be in the document root (the parent directory).
If the .htaccess file is in the /subfolder itself then it will simply never be processed for requests outside of that subfolder in order to rewrite the request.
MrWhite already gave nearly all the explanation I should have attached to my answer. So, like he already stated in his answer, the directives given below should be written into the .htaccess file that is located in the folder where https://site1.co.uk points to for it to work as you expect.
Here are the directives you can use.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /subfolder/$1 [QSA,L]
</IfModule>
The first RewriteCond will help make sure that the request is not for a file that already exists in the folder that the .htaccess file is located.
The second RewriteCond line is similar to the first but this checks for a folder instead. After this line, you can, and probably should, add the REDIRECT_STATUS line from MrWhite's answer. See his answer for the explanation.
The RewriteRule line uses Regular Expressions (RegEx) to effect the rewrite. Remember to replace subfolder on this line to name of the folder you wish to use and this folder should exist in the same location that the .htaccess file is located, and like already explained, this must be the folder that https://site1.co.uk points to.
Hope this helps.
How do I maintain 2 separate .htaccess files so as to avoid dumping rules in the main .htaccess file.
For example: I want all the urls trailing after ^shows(/.*)?$ to point to .htaccess created under controllers/shows (.htaccess)
Depending on your rewrite rules, this can be accomplished with minimal rewriting (heh) of the .htaccess file. Take for example this .htaccess file stored in the webroot /var/www/html:
RewriteEngine On
RewriteRule ^/foo/help/(.*)? /foo/help.php?q=$1
Rewriterule ^blog/(.*)? blog/index.php?id=$1
We're doing two kinds of rewrite here:
www.example.com/foo/help/123 -> wwww.example.com/foo/help.php?q=123
www.example.com/blog/myarticle -> www.example.com/blog/index.php?id=myarticle
Notice the first RewriteRule is using absolute paths, while the second is using a relative path.
If I were to move the first RewriteRule into /var/www/html/foo/.htaccess, the file would look like this:
RewriteEngine On
RewriteRule ^/foo/help/(.*)? /foo/help.php?q=$1
Note that nothing needs to change, since you're using an absolute path.
Now if I were to move the second RewriteRule into /var/www/html/blog/.htaccess, the file would look like this:
RewriteEngine On
RewriteBase /blog/
RewriteRule ^(.*)? index.php?id=$1
Note the paths in the RewriteRule were stripped to make them relative to the current directory, which is now /blog. Also note the RewriteBase directive, which is necessary when using relative rewrite rules in a subdirectory.
Check out this question for another example of using subdirectory .htaccess rewrite rules.
The company I currently work for has a 3+ years live site based on symfony 2.8. Recently it was deployed for testing to a new customer. The images on the original are accessed in the html like "/bundles/bundlename/images/image.png".
On the customers server however the whole thing is under a subfolder, so image url's should be like "/d2s/bundles/bundlename/images/image.png".
We have a .htaccess file in the project's web dir like this:
DirectoryIndex app.php
<IfModule mod_rewrite.c>
RewriteEngine On
FollowSymLinks On
RewriteRule /?bundles/(.*)$ /d2s/bundles/$1 [NC,R=301,L]
# Determine the RewriteBase automatically and set it as environment variable.
# If you are using Apache aliases to do mass virtual hosting or installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the app.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
[,,,]
All other parts work fine, in apache conf's virtualhost AllowOverride is set to All. But this url rewrite just doesn't work, like if it wasn't there at all.
Any idea what can be wrong?
Set a correct RewriteBase. Don't start your internal RewriteRule patterns or substitutions with a /. If you're going to stick with with the auto determination of a RewriteBase equivalent, it should precede all other rules.
I am having a bit of trouble rewriting sub-domains to directories that reside above the web root. I have had plenty of experience with mod_rewrite before, but this particular problem is beyond me.
From what I can tell, mod_rewrite is throwing a tantrum because I insist on using relative directories (..) to determine the directory in which the sub-domain files are located.
Unfortunately, there are two restrictions from my client's specifications:
Putting the sub-domain as a sub-directory of the web root is not an option. The sub-domain must not be accessible from anywhere except the specific sub-domain (there are likely to be directory clashes).
This means http://subdomain.example.com/ must not be accessible from http://example.com/subdomain/ as that directory may be used in the application on the root domain.
An absolute path to the sub-domain files is not known to the client as shared hosting will be used.
If anyone could help me with this problem it would be greatly appreciated! I'd love to start using this in future projects as well, it's quite an elegant solution compared to how we currently deal with sub-domains... If anyone can get it working that is!
Edit: Thought it might be useful to point out that on requesting http://subdomain.example.com/ a 400 Bad Request is returned, rather than a 500 Internal Server Error that I expected. Everything works as expected when requesting the root domain.
Current .htaccess file.
# Begin Rewrite Module for http://*.example.com/
# ==============================================
<IfModule mod_rewrite.c>
# Turn the rewrite engine on.
RewriteEngine On
RewriteBase /
# Map subdomains to their respective directories.
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$
RewriteRule (.*) /../public_subdomains/%1/$1 [L]
# Rewrite all requests for the root domain to always be served through "index.php".
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /index.php/$1 [L]
</IfModule>
Current directory structure.
/
application/
cgi-bin/
framework/
public_html
public/
css/
images/
js/
.htaccess
index.php
public_subdomains/
mysubdomain/
index.php
anothersubdomain/
index.php
How you implement this depends on how your host implements subdomains. Some simply map onto your DOCROOT. Others provide a control panel to allow you to do that subdomain -> subdomain docroot yourself. If (2) applies then what you want is already provided, so I'll assume (1) in this ans.
First point to note is that rewriting in an htaccess per-directory context is really URI mapping botched onto the DOCROOT hierarchy. ".." is not allowed and will throw a 500. In practice your are stuck within the domain's DOCROOT.
So public_domains must be a sub directory of DOCROOT -- in your case public_html.
However, you can still simply prevent any direct access to public_html/public_domains by a simple rule:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} /public_domains(/|$)
RewriteRule ^ - [F,L]
See my Tips for debugging .htaccess rewrite rules for more hints. You only want to barf on requests with public_domains on the entry pass. Also remember that you don't include the leading / and targets are relative to DOCROOT for a base of /.
Trying to orientate myself through the .htaccess jungle, I've now narrated down my rewrite problems to one - adding a language suffix upon entering the page / typing in an address that doesn't have such one.
For example: a visitor types mysite.com/kontakt. This should take them to the default language of the site, i.e. mysite.com/sv/kontakt. Or, just typing in mysite.com should take him/her to mysite.com/sv/.
I'm developing this site locally using MAMP, and the site is located in a subdirectory, and here's the tricky part... How do I sort this out in the .htaccess file?
Current code used:
RewriteBase /mysite/
RewriteCond %{REQUEST_URI} !^(sv|en)
RewriteRule ^(.*)$ sv/$1 [L,R=301]
And that takes me from localhost/mysite/ to localhost/sv/. Not exactly right.
Try this one:
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /mysite/
RewriteRule ^(?!(?:sv|en)/)(.*)$ sv/$1 [R=301,L]
This needs to be placed into .htaccess file into /mysite/ folder.
If accessing localhost/mysite/sv without trailing slash, the rule will redirect it to localhost/mysite/sv/sv as it expects that the language part (sv or en) will be followed by the slash /.
P.S.
And look into setting up a VirtualHost -- then there will be much less (if none at all) of such "tricky parts" with accessing your website via http://localhost/mysite/sv/kontakt (I'm sure you will agree, that http://mysite.dev/sv/kontakt sounds and looks better).