mod_rewrites in nested .htaccess causing strange 404 - apache

I have an apache HTTP server with a directory structure as such:
/
---- api/
---- ---- index.php
---- ---- .htaccess
---- index.php
---- .htaccess
/.htaccess:
DirectorySlash Off
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.*[^/])$ $1/
/api/.htaccess
RewriteEngine On
My objective was to display the index.php of a directory when it was called without a trailing backslash. However, calling http://example.com/api results in a 404. Commmenting out the one line in /api/.htaccess causes everything to work as expected.
I'm having a hard time understanding this behavior as the doc for RewriteEngine On says nothing about it. Could someone shed some light on mod_rewrite's workings here?
The directory, zipped up: mega.nz

Commmenting out the one line in /api/.htaccess causes everything to work as expected.
Yes, because in a per-directory context, mod_rewrite directives are not inherited by default (which differs to other modules). By enabling the mod_rewrite engine in a subdirectory you are overriding the mod_rewrite directives in the parent directory - and these directives in the parent directory are required to make your http://example.com/api request work as expected.
Note that the DirectorySlash directive is part of mod_dir, so this is not overridden. So DirectorySlash is still Off. This then results in Apache attempting to serve the directory /api, which fails. (Although I would have expected this to have resulted in a 403, rather than a 404?)
The mod_rewrite directives in the .htaccess file in the document root apply to all subdirectories by default, so there is no need to do anything special here.
If you want to inherit mod_rewrite directives from the parent .htaccess file then you need to look at the RewriteOptions directive - but per-directory inheritance with mod_rewrite has additional caveats.
Since I don't want Apache to send a 301 when a request to a directory doesn't end in a slash.
Ah OK. (Those directives are otherwise rather "unusual"!) However, that 301 redirect is intended to "fix" the request. By internally rewriting the request you now have a potential duplicate content issue.

Related

.htaccess RewriteRule behavior with existing subdirectories

I've been through many of similar questions but I couldn't find this particular case:
Having this structure:
public_html/
q/
.htaccess
index.php
/dirnofixedname1
/dirnofixedname2
/dirnofixedname3
dirnofixednameN are folders that have files to be used by index.php and not to be directly accessible (called like that as I may not enumerate all in the .htaccess file or it would be impractical)
index.php should process incoming requests
The intention is to process requests like:
http://domain/q/dirnofixedname2 with http://domain/q/index.php?q=dirnofixedname2 while still showing http://domain/q/dirnofixedname2. A popular and already solved case indeed.
So that .htaccess file is:
RewriteEngine On
RewriteCond $1 !^(index\.php)
RewriteRule ^(.*)$ index.php?q=$1 [L]
The problem happens that when the request matches those existing directories (thing I want), it works as intended (index.php executes and gets q) but making a redirect to:
http://domain/q/dirnofixedname2/?q=dirnofixedname2
(and showing that in the URL bar), instead of the intended:
http://domain/q/dirnofixedname2
Particularly, if the directory happens to not exist,
http://domain/q/dirthatdoesnotexist
Gets processed correctly by index.php with q as dirthatdoesnotexist (the script obviously dismisses that and returns nothing).
Do you have any ideas about how to avoid that redirect in cases where the subdir exists? (It's practical to have the same dir name as the parameter)
This is happening due to DirectorySlash directive which is by default in On state since you are requesting an actual directory in your URI.
You can turn it off by using:
DirectorySlash Off
Also to mask directory listing use:
Options -Indexes
at top of your .htaccess

htaccess for laravel without affecting subdomains

I'm trying to get htaccess working for laravel 5.4, but without it affecting the sub-domains that are created.
My current htaccess
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
What I've tried is setting an htaccess in the sub-domain folders with the follwing:
RewriteEngine On
As I read elsewhere this should stop the top domain htaccess, yet when for example I have a sub-domain like dev.example.com, it will redirect to dev.example.com/dev
Anyway of getting rid of the /dev at the end?
Folder structure:
app
bootstrap
config
database
public
storage
resources
routes
dev --> subdomain
Upfront, I don't see how this /dev is related to the directives, you have shown. None of them do anything to add a /dev anywhere. Maybe it's just the subdirectory applied somehow.
The claim "this should stop the top domain htaccess" is not entirely true. From Apache - How directives are applied
The configuration directives found in a .htaccess file are applied to the directory in which the .htaccess file is found, and to all subdirectories thereof.
However, it is important to also remember that there may have been .htaccess files in directories higher up. Directives are applied in the order that they are found.
Therefore, a .htaccess file in a particular directory may override directives found in .htaccess files found higher up in the directory tree. And those, in turn, may have overridden directives found yet higher up, or in the main server configuration file itself.
So an .htaccess doesn't stop another .htaccess, but a directive overrides a directive. This means, you may have some directive from one .htaccess and another unrelated directive from the top level .htaccess.
In your case, RewriteEngine on just overrides RewriteEngine on from the main .htaccess file.
If you want to prevent any RewriteRule from the top .htaccess, I would rather try
RewriteEngine off

rewrite rules not working

I use some rewrite rules inside the Apache virtual hosts configuration httpd-vhosts.conf and it works fine there. Because I want to move to a managed server I have to use the .htaccess file because I don't have access to the apache configuration files.
I tried it locally and somehow I don't get this working at all.
Locally I use xampp 1.8.3 (Apache 2.4.10). I put the .htaccess file in the root directory of the virtual host and use this lines for testing
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteRule /testrule /about/about.php [L]
I always get an 404 error when calling localhost/testrule
It works fine when I put it in the httpd-vhosts.conf.
mod_rewrite is enabled and I have set AllowOverride All in the Directory part.
This blog post clearly mention
In VirtualHost context, The Pattern will initially be matched against
the part of the URL after the hostname and port, and before the query
string (e.g. “/app1/index.html”).
In Directory and htaccess context, the Pattern will initially be
matched against the filesystem path, after removing the prefix that
led the server to the current RewriteRule (e.g. “app1/index.html” or
“index.html” depending on where the directives are defined).
So in virtual host context, matches start from /testrule/...
While in .htaccess and <Directory/> context, it matches testrule/...
You can quick check the htaccess rewrite rules here:
http://htaccess.madewithlove.be/ or here:
http://martinmelin.se/rewrite-rule-tester/
Just get rid of the leading slash in the RewriteRule and you are done
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteRule testrule /about/about.php [L]

.htaccess - Redirect all to index.php for root folder or subfolder

I need an .htaccess file that will work whether it is put in the root folder or a subfolder without modification. The script below is the normal one that I've been trying to adapt without success. I tried the solution on htaccess rewrite index.php on root and subfolders and couldn't get it to work.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>
Layout
.htaccess
index.php
subfolder1
- .htaccess
- index.php
The route /blah should go to /index.php and /subfolder1/whatever should go to /subfolder1/index.php. Currently, the above script will send /subfolder1/whatever to /index.php.
[Update]
This should also work for any path under subfolder1, like /subfolder1/1/2/3/idunno.
If you are using Apache 2.2.16 and later, you can just stop using mod_rewrite, which although extremely useful and powerful, can get messy as hell.
A new directive in mod_dir was introduced, FallbackResource which does just that, redirecting to the uri of your choice if there is no hit on the file system. It is available in .htaccess files as long as AllowOverride Indexes is specified for the directories in the configuration.
As .htaccess files are evaluated depth-first, you just have to have each .htaccess file describe your fallback resource in the current directory, and the one in the subdirectory subfolder1 will take precedence:
subfolder1/.htaccess:
FallbackResource index.php
.htaccess:
FallbackResource index.php
They're both the same, and work just right.
It seems this directive is not well known yet even though it's been around for a few years, and its goal is precisely to solve that problem in an elegant way.
There is only one limitation with that setup. Calling urls in non-existing sub-directories of the root dir or subfolder1 will yield subrequest recursion and subsequently an error 500, because the fallback resource is local to the given directory.
The best approach is to have absolute uris (beginning with '/') as parameter to FallbackResource, which is why it is true that the requirement in itself is kind of odd, and is probably not playing too well with the inner workings of Apache.

Apache .htaccess to redirect index.html to root, why FollowSymlinks and RewriteBase?

In order to redirect all somefolder/index.html (and also somefolder/index.htm) to somefolder/ I use this simple rewrite rule in Apache .htaccess file:
RewriteEngine on
RewriteCond %{THE_REQUEST} ^.*\/index\.html?\ HTTP/
RewriteRule ^(.*)index\.html?$ "/$1" [R=301,L]
This works well!
But at Google groups they suggest to add also:
Options +FollowSymlinks
RewriteBase /
Could anyone be so kind to explain me why would i have to add these last lines, and explain me a bit what they mean and what they do?
Is there a potential secuirty risk in not adding these lines?
Many thanks,
Why they're suggested:
It's suggested that you add Options +FollowSymlinks because it's necessary that symlink following is enabled for mod_rewrite to work, and there's a chance that, while you may be allowed to turn it on, it's not enabled by the main server configuration. I suspect the reason that symlink following is necessary is beause the module makes a number of calls to apr_stat(), which looks like it needs to follow symlinks in order to get file information in all cases.
As for RewriteBase, it's typically not necessary. The documentation goes on about it, but as most people's files do live under the DocumentRoot somewhere, it usually only serves a purpose if you're redirecting externally and you use directory-relative URLs. To illustrate what I mean, consider the following:
RewriteEngine On
RewriteRule ^redirect index.html [R,L]
A request for example.com/redirect will result in an external redirect to example.com/full/path/to/web/root/index.html. The reason for this is that before it handles the redirection, mod_rewrite re-appends the current directory path (which is the default value of RewriteBase). If you modified RewriteBase to be /, then the path information would be replaced with that string, so a request for index.html would now be a request for /index.html.
Note that you could just have done this explicitly on the replace too, regardless of the value of RewriteBase:
RewriteEngine On
RewriteRule ^redirect /index.html [R,L]
...works as intended, for example. However, if you had many rules that needed a common base and were being shifted around between directories, or your content wasn't under the root, it would be useful to appropriately set RewriteBase in that case.
The risk of not using them:
There's absolutely no security risk in not specifying Options +FollowSymlinks, because if you don't and it's not set by the main server configuration, mod_rewrite will always return 403 Forbidden. That's kind of problematic for people trying to view your content, but it definitely doesn't give them any extended opportunity to exploit your code.
Not setting RewriteBase could expose the path to your web content if you had an improperly configured rule set in one of your .htaccess files, but I'm not sure that there's any reason to consider that a security risk.