Questioner Questioner - 3 months ago 20
Apache Configuration Question

How do I create an exception for my htaccess setting that enables friendly URLs?

I have a LAMP server, but I do more website coding and design than Apache configuration. I hope my question will be clear because I don't understand the syntax of

.htaccess
files very well, and the code I have is mostly derived from tutorials on the web.

My website uses "friendly URLs", and to enable that function, I have the following code in my
.htaccess
file:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*) index.php


However, I've created a subdirectory with a whole different set of HTML under a subdirectory that I want to be able to access by going to a URL like this:
http://www.example.com/subdirectory
.

What is happening is that even if I go directly to
http://www.example.com/subdirectory/index.html
, Apache still redirects to
index.php
in the root.

Is there a way I can modify my
.htaccess
file so that my
subdirectory
will be exempted from the redirection?




UPDATE:
After some experimenting, I've determined that it is exactly this line that is causing the problem (which may be obvious to people more skilled than I am with .htaccess files):

RewriteRule ^(.*) index.php


If I comment that line out, everything in the subdirectory works fine (the rest of the site, of course, breaks). If I leave it in, I get the problem described above.

As suggested in an answer below, I tried changing the line to:

RewriteRule !^subdirectory index.php


But that didn't fix the problem. I also tried making a .htaccess file in the subdirectory with these contents:

RewriteEngine On


Unfortunately, that did nothing.

My limited understanding of .htaccess syntax says that the line I already have should leave the contents of my subdirectory alone, but it is acting far more aggressively than intended.

Is there a way I can diagnose and fix this line so that it does not act upon the contents of my subdirectory?




UPDATE 2:

After some experimentation, I found that the .htaccess file in the subdirectory is not being read. If I put gibberish text in it, I don't get any errors, which seems to indicate it's not even being accessed.

I looked for reasons why my .htaccess file might not be being read, and I found that in my .conf file for the site, I need to have this code:

AllowOverride All


I have that directive in there, but the .htaccess in the subdirectory is still not being read.

What to I do to ensure the .htaccess file in the subdirectory is being read?




Contents of my root .htaccess file:

# BEGIN Compress text files
<IfModule mod_deflate.c>
<FilesMatch "\.(css|js|x?html?|php)$">
SetOutputFilter DEFLATE
</FilesMatch>
</IfModule>
# END Compress text files
# BEGIN Expire headers
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 seconds"
ExpiresByType image/x-icon "access plus 2592000 seconds"
ExpiresByType image/jpeg "access plus 2592000 seconds"
ExpiresByType image/png "access plus 2592000 seconds"
ExpiresByType image/gif "access plus 2592000 seconds"
ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds"
ExpiresByType text/css "access plus 604800 seconds"
ExpiresByType text/javascript "access plus 2592000 seconds"
ExpiresByType application/javascript "access plus 2592000 seconds"
ExpiresByType application/x-javascript "access plus 2592000 seconds"
ExpiresByType text/html "access plus 600 seconds"
ExpiresByType application/xhtml+xml "access plus 600 seconds"
</IfModule>
# END Expire headers
# BEGIN Cache-Control Headers
<IfModule mod_headers.c>
<FilesMatch "\.(ico|jpe?g|png|gif|swf)$">
Header set Cache-Control "max-age=2592000, public"
</FilesMatch>
<FilesMatch "\.(css)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
<FilesMatch "\.(js)$">
Header set Cache-Control "max-age=216000, private"
</FilesMatch>
<FilesMatch "\.(x?html?|php)$">
Header set Cache-Control "max-age=600, private, must-revalidate"
</FilesMatch>
</IfModule>
# END Cache-Control Headers
# BEGIN Turn ETags Off
<IfModule mod_headers.c>
Header unset ETag
</IfModule>
FileETag None
# END Turn ETags Off
# BEGIN Remove Last-Modified Header
<IfModule mod_headers.c>
Header unset Last-Modified
</IfModule>
# END Remove Last-Modified Header

# Make all requests pass through index.php to enable "friendly URLs"
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*) index.php

# Turn off 'magic quotes'
php_value magic_quotes_gpc off

# Do not allow Perl script hackers, as they are probably just feeding useless Adsense "directory" sites
RewriteBase /
RewriteCond %{HTTP_USER_AGENT} libwww-perl.*
RewriteRule .* - [F,L]

# Filter for most common exploits
RewriteCond %{HTTP_USER_AGENT} libwww-perl [OR]
RewriteCond %{QUERY_STRING} tool25 [OR]
RewriteCond %{QUERY_STRING} cmd.txt [OR]
RewriteCond %{QUERY_STRING} cmd.gif [OR]
RewriteCond %{QUERY_STRING} r57shell [OR]
RewriteCond %{QUERY_STRING} c99 [OR]

# deny most common except .php
<FilesMatch "\.(inc|tpl|h|ihtml|sql|ini|conf|class|bin|spd|theme|module)$">
deny from all
</FilesMatch>

# Disable .htaccess viewing from browser
<Files ~ "^\.ht">
Order allow,deny
Deny from all
Satisfy All
</Files>





This code is in my
/etc/apche2/apache2.conf
:

# Sets the default security model of the Apache2 HTTPD server. It does
# not allow access to the root filesystem outside of /usr/share and /var/www.
# The former is used by web applications packaged in Debian,
# the latter may be used for local directories served by the web server. If
# your system is serving content from a sub-directory in /srv you must allow
# access here, or in any related virtual host.
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>

<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>

<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>

#<Directory /srv/>
# Options Indexes FollowSymLinks
# AllowOverride None
# Require all granted
#</Directory>

# AccessFileName: The name of the file to look for in each directory
# for additional configuration directives. See also the AllowOverride
# directive.
#
AccessFileName .htaccess


... and here is the contents of the conf file specific to the site in question:

<VirtualHost *:80>
ServerName www.local_example.com
ServerAlias local_example.com
ServerAdmin serveradmin@gmail.com

DocumentRoot /var/www/example.com
<Directory /var/www/example.com/>
Options Indexes FollowSymLinks MultiViews
# pcw AllowOverride None
AllowOverride All
Order allow,deny
allow from all
# This directive allows us to have apache2's default start page
# in /apache2-default/, but still have / go to the right place
# Commented out for Ubuntu
#RedirectMatch ^/$ /apache2-default/
</Directory>

ErrorLog /home/admin/Apache_Logs/local_example.com_error.log

# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel debug

CustomLog /home/admin/Apache_Logs/local_example.com_access.log combined
ServerSignature On

</VirtualHost>

Answer

If /subdirectory is a physical directory on the filesystem and /subdirectory/index.html is an actual file then your current directives already include the necessary exception... the URL should not be rewritten if the requested URL maps to a physical directory or file.

However, to explicitly include an exception for the /subdirectory then you could do something like:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !^subdirectory index.php

Only URLs that do not start /subdirectory will be processed. (Not that the directory-prefix is removed when matching the URL-path with the RewriteRule pattern, so it should be subdirectory here, not /subdirectory.)

Alternatively, you can create an additional .htaccess at /subdirectory/.htaccess and simply enable the rewrite engine:

# /subdirectory/.htaccess
RewriteEngine On

mod_rewrite directives are not inherited by default, so this should completely override the mod_rewrite directives in the parent .htaccess file. (Note that other directives from different modules might still be processed.)


UPDATE: I cannot see anything in your .htaccess file that would directly cause these symptoms, however, the following does need fixing/tidying...

# Do not allow Perl script hackers, as they are probably just feeding useless Adsense "directory" sites
RewriteBase /
RewriteCond %{HTTP_USER_AGENT} libwww-perl.*
RewriteRule .* - [F,L]

# Filter for most common exploits
RewriteCond %{HTTP_USER_AGENT} libwww-perl [OR]
RewriteCond %{QUERY_STRING} tool25 [OR]
RewriteCond %{QUERY_STRING} cmd.txt [OR]
RewriteCond %{QUERY_STRING} cmd.gif [OR]
RewriteCond %{QUERY_STRING} r57shell [OR]
RewriteCond %{QUERY_STRING} c99 [OR]

The 2nd code block above ("Filter for most common exploits") is incomplete and should not have a trailing OR flag (that would potentially block everyone!). These two code blocks also repeat the same code and should be combined. The RewriteBase directive is also redundant and can be removed. The above should be rewritten as:

# Do not allow Perl script hackers, as they are probably just feeding useless Adsense "directory" sites
# and Filter for most common exploits
RewriteCond %{HTTP_USER_AGENT} libwww-perl [OR]
RewriteCond %{QUERY_STRING} tool25 [OR]
RewriteCond %{QUERY_STRING} cmd.txt [OR]
RewriteCond %{QUERY_STRING} cmd.gif [OR]
RewriteCond %{QUERY_STRING} r57shell [OR]
RewriteCond %{QUERY_STRING} c99
RewriteRule .* - [F]

The F flag implies L, so the L flag is not required here.


UPDATE#2: Again, I cannot see anything in your VirtualHost container that would cause these problems (although, to be honest, I'm struggling to even imagine what could be causing this behaviour).

However, the following line is suspicious:

Options Indexes FollowSymLinks MultiViews

Why do you need MultiViews? Also, do you need Indexes? Most sites will disable these options as they can expose your file structure and result in unexpected behaviour (unless that behaviour is intentional of course). However, FollowSymLinks is required for mod_rewrite.

If these options are not required then try removing them:

Options FollowSymLinks

Incidentally, these options can also be disabled in .htaccess with the following directive (note that here the options are preceded with -):

Options -Indexes -MultiViews