Community Documentation

Clean URLs with Apache 2 for performance

Last updated December 13, 2010. Created by Amazon on January 8, 2006.
Edited by ghoti, recrit, mikeytown2, jbrauer. Log in to edit this page.

Note the following directions do not adequately cover everything that needs to be included in a site's Apache configuration file to make sure the site is secure. The files directory needs a SetHandler directive per http://drupal.org/files/sa-2006-006/advisory.txt

Enabling .htaccess in Apache requires more work on the part of the server. A full explanation can be found here:
http://www.serverwatch.com/tutorials/article.php/3436911
Suffice it to say that it is in your interest to not use .htaccess files and even disable them if you are concerned about squeezing more performance out of apache.

I moved the rewrite rules (all of the sample .htaccess file really) to /etc/httpd/conf/drupal.conf. Then for each virtual host, one can add the line:

Include conf/drupal.conf

The rewrite rules change slightly:
  # Rewrite current-style URLs of the form 'index.php?q=x'.
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
  RewriteRule ^(.*)$ /index.php?q=$1 [L,QSA]

Note that I added %{DOCUMENT_ROOT} and a leading slash in front of index.php -- because I have index.php installed in my document root. If you install it in another directory, you will want to give the relative path to it from document root with the leading slash.

Important: If you forget the leading slash (more specifically, forget to give the relative path with leading slash), Apache will give you a "400 Bad Request" error.

This is better. But we still have a problem where every request will check for the existence of a file and a directory before we apply the rewrite rule. The OS may be able to cache some of that information, but it would still be better to avoid the two file-system checks in the first place.

There are some directories that we should not rewrite. And there are certain extensions that we should not rewrite. Using this information, we can update the rewrite rule to send everything to index.php that does not fall into this category. The first rule excludes the directories "files", "misc", and "uploads". The second rule excludes the extensions you see. Add more if you have other extensions in your directory that should not get passed to index.php.

  RewriteCond  %{REQUEST_FILENAME} !^/$
  RewriteCond  %{REQUEST_FILENAME} !^/(files|misc|uploads)(/.*)?
  RewriteCond  %{REQUEST_FILENAME} !\.(php|ico|png|jpg|gif|css|js|html?)(\W.*)?
  RewriteRule ^(.*)$ /index.php?q=$1 [L,QSA]

Note: This sort of directive will disable ImageCache and any other modules that depend on passing requests for files that are not found to index.php.

Compliance with SA-2006-006

Multisite + files

Add this to your http.conf file; be sure to change the webroot path /var/www/html/ so it matches your webroot path. Also be aware that if your running drupal in multiple sub directories then you need to add this in for each one. (/var/www/html/sitea, /var/www/html/siteb, /var/www/html/sitec, ...etc) or you can use the directives in the following section. This is compatible with mulitsite due to the * in sites/*/files.

<Directory /var/www/html/sites/*/files>
  SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
  Options None
  Options +FollowSymLinks
</Directory>

Multisite + Sub Directories + files + tmp

The below directives will handle files directories for each site and for any sub directory site. This example also shows how to secure site tmp directories wh any other site specific directory to safeguard. Again, replace /var/www/html/ to match your webroot.

  # handles root (/var/www/html/sites) and sub dirs (/var/html/www/sub/sites)
  <Directory ~ "^/var/www/html/(.+/)*sites/.+/(files|tmp)/">
    SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
    Options None
    Options +FollowSymLinks
  </Directory>

See Directory Directive for the * syntax and other tips.

Comments

Make sure to specify $base_url.

Make sure to specify $base_url when using the %{DOCUMENT_ROOT} method above. Once I did my funky theming errors went away.

See http://drupal.org/node/9418#comment-149892.
--
Rob
Founder and Director
Electronic Insight Corporation

Recent Drupal Projects: MP3PIG | MySpace Layouts

--
Rob Barreca
Drupal Architect
ChipIn, Inc.
Electronic Insight Corporation

Learn how you can contribute to Drupal.

Is it the first, second or both?

I am a real newbie to mod_rewrite and I would like to try this but I cannot figure out whether you use the first set of rules, the second set of rules or both. If you use both how should they be placed?

Do I place them exactly as you have listed them, for example:

  # Rewrite current-style URLs of the form 'index.php?q=x'.
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
  RewriteRule ^(.*)$ /index.php?q=$1 [L,QSA]
  RewriteCond  %{REQUEST_FILENAME} !^/$
  RewriteCond  %{REQUEST_FILENAME} !^/(files|misc|uploads)(/.*)?
  RewriteCond  %{REQUEST_FILENAME} !\.(php|ico|png|jpg|gif|css|js|html?)(\W.*)?
  RewriteRule ^(.*)$ /index.php?q=$1 [L,QSA]

Any help would be really appreciated.

Regards,

ChuckL

Chuckl

Bump

I would really like to know that as well !!! :-)

the second set replaces the

the second set replaces the first,
but is not as robust (i.e. funny things might happen :))), so use with care

Just include (a copy of) .htaccess in the Directory block

I found it even easier than that.
My approach was to leave the .htaccess original nearby, but include it at startup, and ignore it from then on. Basically the same approach, but I didn't discover the need to edit it at all. I placed the include in the directory context and it behaved as it it was found there. Perhaps I'm lucky.

First, get clean URLs working out-of the box, then:
(siteroot is of course /var/www/drupal and the site instance is called drupalsite also. This example is Debian-Ubuntu/Apache2)

mv /var/www/drupalsite/.htaccess /var/www/drupalsite/htaccess.conf

This disables it again temporarily, but leaves the file as part of the site. If you want to copy instead, you must MOVE the .htaccess file away otherwise it will contine to be read.
#> vi /etc/apache2/sites-enabled

<VirtualHost *>
        ServerName drupalsite.example.com
        DocumentRoot /var/www/drupalsite
        <Directory /var/www/sdrupalsite>
                Order allow,deny
                Allow from all
                Options +FollowSymLinks +ExecCGI
                RewriteEngine On
                AllowOverride All

                # Instead of reading .htaccess rules on the fly every page,
                # Include them once, now, in this directory context
                Include /var/www/drupalsite/htaccess.conf
        </Directory>
</VirtualHost *>

#> apache2ctl -t
#> apache2ctl restart

The rewrite rules or .htaccess file from the Drupal distro did not have to be modified at all, and I did not have to hardcode a $base_url in my settings.conf.

So far so good. I've not tested with subdirectories yet.

The tips on skipping filename extensions are probably good, but may conflict with 'private' file storage issues.

.dan.
How to troubleshoot Drupal | http://www.coders.co.nz/

Why not just point to the file directly?

<VirtualHost 192.168.1.2:80>
DocumentRoot /home/drupal
ServerName example.com
ErrorLog /var/log/httpd/sites/example.com_error-log
CustomLog /var/log/httpd/sites/example.com_access-log "combined"

<IfModule mod_rewrite.c>
RewriteLog logs/sites/example.com_rewrite-log
#RewriteLogLevel debug
</IfModule>

<Directory "/home/drupal/>
AllowOverride none
# Read in Drupal default .htaccess file asif conf
Include /home/drupal/.htaccess
</Directory>

</VirtualHost>

The above seems to work fine for me. Plus, if you maintain a cvs version of drupal right next to live copy then all you have to do is run a diff to get updates for security changes.

diff -ur older_folder/ newer_folder/ > drupal-update.diff

Then apply the patch after review and you have a very quick system of updating.

-------------------------------------------------------------------
Helping to contribute - by sharing what I know.
Drupal Videos at GotDrupal.com

Well...

Yes, I could have turned off AllowOverride altogether, as you did, but I chose not to. I have an eclectic bunch of sites, and I sorta liked having it around. Disabling it altogether didn't make me happy, as it would leave me headscratching at some later date about why the **** something obvious wasn't working...

For the performance boost, tweaking apache2.conf even more will probably be even more successful I guess.

.dan.
How to troubleshoot Drupal | http://www.coders.co.nz/

Neat

This worked for me - it took me a while to realise that I had a wrong path in the Directory directive, but once that was fixed it was fine. I much prefer it to the alternative methods described above.

The only criticism I would make is that it is a bit misleading to disallow Override in httpd.conf, while having an .htaccess file that is in force by a different means. It might be a bit puzzling for anyone trying to fix a problem. Comments in httpd.conf are essential.

Clearing someting

Hello there
Since I started on Drupal, I had this problem with URL cleaner.
Seriousle for a beginner this tutorial is just messy I didn't even know which file to edit or sth like this..
Could you please mak e a more step by step one if its possible
Thanks
Altin

Drupal clean URL FIX

nobody click here