Pages

Subscribe

Ultimate htaccess Examples

Here's my list of the ultimate htaccess code snippets and examples that I use all the time. I tried to keep them extremely minimalistic.
Don't miss checking out this example htaccess file, its very comprehensive

Heres the actual code that I use when I'm developing sites for clients

This lets google crawl the page, lets me access the whole site (24.205.23.222) without a password, and lets my client access the page WITH a password. It also allows for XHTML and CSS validation! (w3.org)

# ELITE HTACCESS FOR WEBDEVELOPERS
##############################################
AuthName "SiteName Administration"
AuthUserFile /home/sitename.com/.htpasswd
AuthType basic
Require valid-user
Order deny,allow
Deny from all
Allow from 24\.205\.23\.222
Allow from w3.org htmlhelp.com
Allow from googlebot.com
Satisfy Any
Each code snippet has been copied from htaccesselite. Additional and detailed info on each htaccess code snippet can be found at askapache.com
NOTE: Most of these snippets can be used with a Files or Filesmatch directive to only apply to certain files.
NOTE: Any htaccess rewrite examples should always begin with:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /

Apache Documentation: 1.3 | 2.0 | 2.2 | Current

Make any file be a certain filetype (regardless of name or extension)

#Makes image.gif, blah.html, index.cgi all act as php
ForceType application/x-httpd-php

Redirect non-https requests to https server fixing double-login problem and ensuring that htpasswd authorization can only be entered using HTTPS

Additional https/ssl information and Apache SSL in htaccess examples
SSLOptions +StrictRequire
SSLRequireSSL
SSLRequire %{HTTP_HOST} eq "google.com"
ErrorDocument 403 https://google.com

SEO Friendly redirects for bad/old links and moved links

For single moved file

Redirect 301 /d/file.html http://www.htaccesselite.com/r/file.html

For multiple files like a blog/this.php?gh

RedirectMatch 301 /blog(.*) http://www.askapache.com/$1

different domain name

Redirect 301 / http://www.newdomain.com

Require the www

Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/robots\.txt$
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]

Require the www without hardcoding

Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/robots\.txt$ [NC]
RewriteCond %{HTTP_HOST} !^www\.[a-z-]+\.[a-z]{2,6} [NC]
RewriteCond %{HTTP_HOST} ([a-z-]+\.[a-z]{2,6})$ [NC]
RewriteRule ^/(.*)$ http://%1/$1 [R=301,L]

Require no subdomain

Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/robots\.txt$
RewriteCond %{HTTP_HOST} \.([a-z-]+\.[a-z]{2,6})$ [NC]
RewriteRule ^/(.*)$ http://%1/$1 [R=301,L]

Require no subdomain

Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} \.([^\.]+\.[^\.0-9]+)$
RewriteCond %{REQUEST_URI} !^/robots\.txt$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

Redirect everyone to different site except 1 IP address (useful for web-development)

ErrorDocument 403 http://www.someothersite.com
Order deny,allow
Deny from all
Allow from 24.33.65.6

CHMOD your files

chmod .htpasswd files 640 chmod .htaccess files 644 chmod php files 600 chmod files that you really dont want people to see as 400 NEVER chmod 777, if something requires write access use 766

Variable (mod_env) Magic

Set the Timezone of the server:

SetEnv TZ America/Indianapolis

Set the Server Administrator Email:

SetEnv SERVER_ADMIN webmaste@htaccesselite.com

Turn off the ServerSignature

ServerSignature Off

Add a "en-US" language tag and "text/html; UTF-8" headers without meta tags

Article: Setting Charset in htaccess
Article: Using FilesMatch and Files in htaccess
AddDefaultCharset UTF-8
# Or AddType 'text/html; charset=UTF-8' html
DefaultLanguage en-US

Using the Files Directive


   AddDefaultCharset UTF-8
   DefaultLanguage en-US

Using the FilesMatch Directive (preferred)


   AddDefaultCharset UTF-8
   DefaultLanguage en-US

Use a custom php.ini with mod_php or php as a cgi

Article: Custom PHP.ini tips and tricks
When php run as Apache Module (mod_php) in root .htaccess SetEnv PHPRC /location/todir/containing/phpinifile When php run as CGI Place your php.ini file in the dir of your cgi’d php, in this case /cgi-bin/ htaccess might look something like this AddHandler php-cgi .php .htm Action php-cgi /cgi-bin/php5.cgi When cgi’d php is run with wrapper (for FastCGI) You will have a shell wrapper script something like this: #!/bin/sh export PHP_FCGI_CHILDREN=3 exec /user3/x.com/htdocs/cgi-bin/php5.cgi Change To #!/bin/sh export PHP_FCGI_CHILDREN=3 exec /x.com/cgi-bin/php.cgi -c /abs/path/to/php.ini

Securing directories: Remove the ability to execute scripts

Heres a couple different ways I do it
AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi
Options -ExecCGI
This is cool, you are basically categorizing all those files that end in those extensions so that they fall under the jurisdiction of the -ExecCGI command, which also means -FollowSymLinks (and the opposite is also true, +ExecCGI also turns on +FollowSymLinks)

Only allow GET and PUT request methods to your server.

Options -ExecCGI -Indexes -All +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_METHOD} !^(GET|PUT)
RewriteRule .* - [F]

Processing All gif files to be processed through a cgi script

Action image/gif /cgi-bin/filter.cgi

Process request/file depending on the request method

Script PUT /cgi-bin/upload.cgi

Force Files to download, not be displayed in browser

AddType application/octet-stream .avi
AddType application/octet-stream .mpg
Then in your HTML you could just link directly to the file..
And then you will get a pop-up box asking whether you want to save the file or open it.

Show the source code of dynamic files

If you'd rather have .pl, .py, or .cgi files displayed in the browser as source rather than be executed as scripts, simply create a .htaccess file in the relevant directory with the following:
RemoveHandler cgi-script .pl .py .cgi

Dramatically Speed up your site by implementing Caching!

Article: Speed Up Sites with htaccess Caching
# MONTH

   Header set Cache-Control "max-age=2592000"


# WEEK

   Header set Cache-Control "max-age=604800"


# DAY

   Header set Cache-Control "max-age=43200"

Prevent Files image/file hotlinking and bandwidth stealing

Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?askapache.com/.*$ [NC]
RewriteRule \.(gif|jpg|swf|flv|png)$ http://www.askapache.com/feed.gif [R=302,L]

ErrorDocuments

Article: Additional ErrorDocument Info and Examples
ErrorDocument 404 /favicon.ico
ErrorDocument 403 https://secure.htaccesselite.com
ErrorDocument 404 /cgi-bin/error.php
ErrorDocument 400 /cgi-bin/error.php
ErrorDocument 401 /cgi-bin/error.php
ErrorDocument 403 /cgi-bin/error.php
ErrorDocument 405 /cgi-bin/error.php
ErrorDocument 406 /cgi-bin/error.php
ErrorDocument 409 /cgi-bin/error.php
ErrorDocument 413 /cgi-bin/error.php
ErrorDocument 414 /cgi-bin/error.php
ErrorDocument 500 /cgi-bin/error.php
ErrorDocument 501 /cgi-bin/error.php
Note: You can also do an external link, but don't do an external link to your site or you will cause a loop that will hurt your SEO.

Authentication Magic

Require password for 1 file:


   AuthName "Prompt"
   AuthType Basic
   AuthUserFile /home/askapache.com/.htpasswd
   Require valid-user

Protect multiple files:


   AuthName "Development"
   AuthUserFile /.htpasswd
   AuthType basic
   Require valid-user

Example uses of the Allow Directive:

# A (partial) domain-name
Allow from 10.1.0.0/255.255.0.0

# Full IP address
Allow from 10.1.2.3

# More than 1 full IP address
Allow from 192.168.1.104 192.168.1.205

# Partial IP addresses
# first 1 to 3 bytes of IP, for subnet restriction.
Allow from 10.1
Allow from 10 172.20 192.168.2

# network/netmask pair
Allow from 10.1.0.0/255.255.0.0

# network/nnn CIDR specification
Allow from 10.1.0.0/16

# IPv6 addresses and subnets
Allow from 2001:db8::a00:20ff:fea7:ccea
Allow from 2001:db8::a00:20ff:fea7:ccea/10

Using visitor dependent environment variables:

Article: Additional SetEnvIf examples
SetEnvIf User-Agent ^KnockKnock/2\.0 let_me_in
Order Deny,Allow
Deny from all
Allow from env=let_me_in

Allow from apache.org but deny from foo.apache.org

Order Allow,Deny
Allow from apache.org
Deny from foo.apache.org

Allow from IP address with no password prompt, and also allow from non-Ip address with password prompt:

AuthUserFile /home/www/site1-passwd
AuthType Basic
AuthName MySite
Require valid-user
Allow from 172.17.10
Satisfy Any

block access to files during certain hours of the day

Options +FollowSymLinks
RewriteEngine On
RewriteBase /
# If the hour is 16 (4 PM) Then deny all access
RewriteCond %{TIME_HOUR} ^16$
RewriteRule ^.*$ - [F,L]

A good default example .htaccess file

I use this when I start a new site, and uncomment or delete parts of the file depending on the sites needs
# DEFAULT SETTINGS
##############################################
Options +ExecCGI -Indexes
DirectoryIndex index.php index.html index.htm

### DEFAULTS ###
ServerSignature Off
AddType video/x-flv .flv
AddType application/x-shockwave-flash .swf
AddType image/x-icon .ico
AddDefaultCharset UTF-8
DefaultLanguage en-US
SetEnv TZ America/Indianapolis
SetEnv SERVER_ADMIN webmaster@askapache.com

### FAST-CGI ###
AddHandler fastcgi-script fcgi
AddHandler php-cgi .php
Action php-cgi /cgi-bin/php5-wrapper.fcgi



# HEADERS and CACHING
##############################################
#### CACHING ####
# YEAR

   Header set Cache-Control "max-age=2592000"

# WEEK

   Header set Cache-Control "max-age=604800"

# 10 minutes

   Header set Cache-Control "max-age=600"

# DONT CACHE

   Header unset Cache-Control




# REWRITES AND REDIRECTS
##############################################
### SEO REDIRECTS ###
Redirect 301 /2006/uncategorized/^^.html http://www.^^SITE^^.^^TLD^^

### REWRITES ###
RewriteEngine On
RewriteBase /

### WORDPRESS ###
# BEGIN WordPress

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]


# END WordPress



# AUTHENTICATION
##############################################
AuthName "askapache.com"
Require valid-user
AuthUserFile /askapache/.htpasswd
AuthType basic

.htaccess File and mod_rewrite examples

An attempt to create a default skeleton .htaccess file with the very best apache htaccess examples... Updated semi-frequently based on detailed info from the Apache htaccess tutorial.
If you see any room for improvement, or if you can add something than go ahead and comment and I will definately give it a look for possible inclusion.

NOTE:
Check out and use the Google 404 Error Page.

=============================================================================#
          MAIN SETTINGS AND OPTIONS
=============================================================================#
 Options: ALL,FollowSymLinks,Includes,IncludesNOEXEC,SymLinksIfOwnerMatch
##########
 
## MAIN DEFAULTS ###
Options +ExecCGI -Indexes
DirectoryIndex index.html index.htm index.php
DefaultLanguage en-US
AddDefaultCharset UTF-8
ServerSignature Off
 
## ENVIRONMENT VARIABLES ###
SetEnv PHPRC /webroot/includes
SetEnv TZ America/Indianapolis
SetEnv SERVER_ADMIN webmaster@domain.tld
 
## MIME TYPES ###
AddType video/x-flv .flv
AddType application/x-shockwave-flash .swf
AddType image/x-icon .ico
 
## FORCE FILE TO DOWNLOAD INSTEAD OF APPEAR IN BROWSER ###
-> http://www.htaccesselite.com/addtype-addhandler-action-vf6.html
AddType application/octet-stream .mov .mp3 .zip
 
## ERRORDOCUMENTS ###
 
-> http://askapache.com/htaccess/apache-status-code-headers-errordocument.html
 
======== 1xx
ErrorDocument 100 /error-100/
ErrorDocument 101 /error-101/
ErrorDocument 102 /error-102/
======== 2xx
ErrorDocument 200 /error-200/
ErrorDocument 201 /error-201/
ErrorDocument 202 /error-202/
ErrorDocument 203 /error-203/
ErrorDocument 204 /error-204/
ErrorDocument 205 /error-205/
ErrorDocument 206 /error-206/
ErrorDocument 207 /error-207/
======== 4xx
ErrorDocument 400 /error-400/
ErrorDocument 401 /error-401/
ErrorDocument 402 /error-402/
ErrorDocument 403 /error-403/
ErrorDocument 404 /error-404/
ErrorDocument 405 /error-405/
ErrorDocument 406 /error-406/
ErrorDocument 407 /error-407/
ErrorDocument 408 /error-408/
ErrorDocument 409 /error-409/
ErrorDocument 410 /error-410/
ErrorDocument 411 /error-411/
ErrorDocument 412 /error-412/
ErrorDocument 413 /error-413/
ErrorDocument 414 /error-414/
ErrorDocument 415 /error-415/
ErrorDocument 416 /error-416/
ErrorDocument 417 /error-417/
ErrorDocument 418 /error-418/
ErrorDocument 419 /error-419/
ErrorDocument 420 /error-420/
ErrorDocument 421 /error-421/
ErrorDocument 422 /error-422/
ErrorDocument 423 /error-423/
ErrorDocument 424 /error-424/
ErrorDocument 425 /error-425/
ErrorDocument 426 /error-426/
======== 5xx
ErrorDocument 500 /error-500/
ErrorDocument 501 /error-501/
ErrorDocument 502 /error-502/
ErrorDocument 503 /error-503/
ErrorDocument 504 /error-504/
ErrorDocument 505 /error-505/
ErrorDocument 506 /error-506/
ErrorDocument 507 /error-507/
ErrorDocument 508 /error-508/
ErrorDocument 509 /error-509/
ErrorDocument 510 /error-510/
 
AddLanguage aa .aa # Afar
AddLanguage ab .ab # Abkhazian
AddLanguage af .af # Afrikaans
AddLanguage am .am # Amharic
AddLanguage ar .ar # Arabic
AddLanguage as .as # Assamese
AddLanguage ay .ay # Aymara
AddLanguage az .az # Azerbaijani
AddLanguage ba .ba # Bashkir
AddLanguage be .be # Byelorussian
AddLanguage bg .bg # Bulgarian
AddLanguage bh .bh # Bihari
AddLanguage bi .bi # Bislama
AddLanguage bn .bn # Bengali; Bangla
AddLanguage bo .bo # Tibetan
AddLanguage br .br # Breton
AddLanguage ca .ca # Catalan
AddLanguage co .co # Corsican
AddLanguage cs .cs # Czech
AddLanguage cy .cy # Welsh
AddLanguage da .da # Danish
AddLanguage de .de # German
AddLanguage dz .dz # Bhutani
AddLanguage el .el # Greek
AddLanguage en .en # English
AddLanguage eo .eo # Esperanto
AddLanguage es .es # Spanish
AddLanguage et .et # Estonian
AddLanguage eu .eu # Basque
AddLanguage fa .fa # Persian
AddLanguage fi .fi # Finnish
AddLanguage fj .fj # Fiji
AddLanguage fo .fo # Faeroese
AddLanguage fr .fr # French
AddLanguage fy .fy # Frisian
AddLanguage ga .ga # Irish
AddLanguage gd .gd # Scots Gaelic
AddLanguage gl .gl # Galician
AddLanguage gn .gn # Guamni
AddLanguage gu .gu # Gujarati
AddLanguage ha .ha # Hausa
AddLanguage he .he # Hebrew
AddLanguage hi .hi # Hindi
AddLanguage hr .hr # Croatian
AddLanguage hu .hu # Hungarian
AddLanguage hy .hy # Armenian
AddLanguage ia .ia # Interlingua
AddLanguage id .id # Indonesian
AddLanguage ie .ie # lnteriingue
AddLanguage ik .ik # Knupiak
AddLanguage is .is # Icelandic
AddLanguage it .it # Italian
AddLanguage iu .iu # Inuktitut (Eskimo)
AddLanguage ja .ja # Japanese
AddLanguage jw .jw # Javanese
AddLanguage ka .ka # Georgian
AddLanguage kk .kk # Kazakh
AddLanguage kl .kl # Greaenlandic
AddLanguage km .km # Cambodian
AddLanguage kn .kn # Kannada
AddLanguage ko .ko # Korean
AddLanguage ks .ks # Kashmiri
AddLanguage ku .ku # Kurdish
AddLanguage ky .ky # Kirghiz
AddLanguage la .la # Latin
AddLanguage ln .ln # Lingala
AddLanguage lo .lo # Laothian
AddLanguage lt .lt # Lithuainnian
AddLanguage lv .lv # Latvian, Lettish
AddLanguage mg .mg # Malagasy
AddLanguage mi .mi # Maori
AddLanguage mk .mk # Macedonian
AddLanguage ml .ml # Malayalam
AddLanguage mn .mn # Mongolian
AddLanguage mo .mo # Moldavian
AddLanguage mr .mr # Marathi
AddLanguage ms .ms # Malay
AddLanguage mt .mt # Maltese
AddLanguage my .my # Burmese
AddLanguage na .na # Nauru
AddLanguage ne .ne # Nepali
AddLanguage nl .nl # Dutch
AddLanguage no .no # Norwegian
AddLanguage oc .oc # Occitan
AddLanguage om .om # (Afan) Oromo
AddLanguage or .or # Oriya
AddLanguage pa .pa # Punjabi
AddLanguage pl .po # Polish (use .po instead .pl to avoid problems with perl files)
AddLanguage ps .ps # Pashto, Pushto
AddLanguage pt .pt # Portuguese
AddLanguage qu .qu # Ouechua
AddLanguage rm .rm # Rhaeto-Romance
AddLanguage rn .rn # Kirundi
AddLanguage ro .ro # Romanian
AddLanguage ru .ru # Russian
AddLanguage rw .rw # Kinya, Rwanda
AddLanguage sa .sa # Sanskrit
AddLanguage sd .sd # Sindhi
AddLanguage sg .sg # Sangro
AddLanguage sh .sh # Serbo-Croatian
AddLanguage si .si # Singhalese
AddLanguage sk .sk # Slovak
AddLanguage sl .sl # Slovenian
AddLanguage sm .sm # Samoan
AddLanguage sn .sn # Shona
AddLanguage so .so # Somali
AddLanguage sq .sq # Albanian
AddLanguage sr .sr # Serbian
AddLanguage ss .ss # Siswati
AddLanguage st .st # Sesotho
AddLanguage su .su # Sundanese
AddLanguage sv .sv # Swedish
AddLanguage sw .sw # Swahili
AddLanguage ta .ta # Tamil
AddLanguage te .te # Tegulu
AddLanguage tg .tg # Tajik
AddLanguage th .th # Thai
AddLanguage ti .ti # Tigrinya
AddLanguage tk .tk # Turkmen
AddLanguage tl .tl # Tagalog
AddLanguage tn .tn # Setswana
AddLanguage to .to # Tonga
AddLanguage tr .tr # Turkish
AddLanguage ts .ts # Tsonga
AddLanguage tt .tt # Tatar
AddLanguage tw .tw # Twi
AddLanguage ug .ug # Uigur
AddLanguage uk .uk # Ukrainian
AddLanguage ur .ur # Urdu
AddLanguage uz .uz # Uzbek
AddLanguage vi .vi # Vietnamese
AddLanguage vo .vo # Volapuek
AddLanguage wo .wo # Wolof
AddLanguage xh .xh # Xhosa
AddLanguage yi .yi # Yiddish
AddLanguage yo .yo # Yoruba
AddLanguage za .za # Zhuang
AddLanguage zh .zh # Chinese
AddLanguage zu .zu # Zulu
 
=============================================================================#
          SCRIPTING, ACTION, ADDHANDLER
=============================================================================#
 Handlers be builtin, included in a module, or added with Action directive
 default-handler: default, handles static content (core)
      send-as-is: Send file with HTTP headers (mod_asis)
      cgi-script: treat file as CGI script (mod_cgi)
       imap-file: Parse as an imagemap rule file (mod_imap)
     server-info: Get server config info (mod_info)
   server-status: Get server status report (mod_status)
        type-map: type map file for content negotiation (mod_negotiation)
  fastcgi-script: treat file as fastcgi script (mod_fastcgi)
##########
 
-> http://www.askapache.com/php/custom-phpini-tips-and-tricks.html
 
## PARSE AS CGI ###
AddHandler cgi-script .cgi .pl .spl
 
## RUN PHP AS APACHE MODULE ###
AddHandler application/x-httpd-php .php .htm
 
## RUN PHP AS CGI ###
AddHandler php-cgi .php .htm
 
## CGI PHP WRAPPER FOR CUSTOM PHP.INI ###
AddHandler phpini-cgi .php .htm
Action phpini-cgi /cgi-bin/php5-custom-ini.cgi
 
## FAST-CGI SETUP WITH PHP-CGI WRAPPER FOR CUSTOM PHP.INI ###
AddHandler fastcgi-script .fcgi
AddHandler php-cgi .php .htm
Action php-cgi /cgi-bin/php5-wrapper.fcgi
 
## CUSTOM PHP CGI BINARY SETUP ###
AddHandler php-cgi .php .htm
Action php-cgi /cgi-bin/php.cgi
 
## PROCESS SPECIFIC FILETYPES WITH CGI-SCRIPT ###
Action image/gif /cgi-bin/img-create.cgi
 
## CREATE CUSTOM HANDLER FOR SPECIFIC FILE EXTENSIONS ###
AddHandler custom-processor .ssp
Action custom-processor /cgi-bin/myprocessor.cgi
 
=============================================================================#
          HEADERS, CACHING AND OPTIMIZATION
=============================================================================#
-> http://www.htaccesselite.com/cache-control-http-headers-vt65.html
      300   5 M
     2700  45 M
     3600   1 H
    54000  15 H
    86400   1 D
   518400   6 D
   604800   1 W
  1814400   3 W
  2419200   1 M
 26611200  11 M
 29030400   1 Y (never expire)
##########
 
### HEADER CACHING ####
-> http://www.askapache.com/htaccess/speed-up-sites-with-htaccess-caching.html
<filesMatch "\.(flv|gif|jpg|jpeg|png|ico)$">
   Header set Cache-Control "max-age=2592000"
</filesMatch>
<filesMatch "\.(js|css|pdf|swf)$">
   Header set Cache-Control "max-age=604800"
</filesMatch>
<filesMatch "\.(html|htm|txt)$">
   Header set Cache-Control "max-age=600"
</filesMatch>
<filesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$">
   Header unset Cache-Control
</filesMatch>
 
## ALTERNATE EXPIRES CACHING ###
-> htaccesselite.com/d/use-htaccess-to-speed-up-your-site-discussion-vt67.html
ExpiresActive On
ExpiresDefault A604800
ExpiresByType image/x-icon A2592000
ExpiresByType application/x-javascript A2592000
ExpiresByType text/css A2592000
ExpiresByType text/html A300
<filesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$">
   ExpiresActive Off
</filesMatch>
 
## META HTTP-EQUIV REPLACEMENTS ###
<filesMatch "\.(html|htm|php)$">
   Header set imagetoolbar "no"
</filesMatch>
 
=============================================================================#
          REWRITES AND REDIRECTS
=============================================================================#
 REQUEST METHODS: GET,POST,PUT,DELETE,CONNECT,OPTIONS,PATCH,PROPFIND,
                  PROPPATCH,MKCOL,COPY,MOVE,LOCK,UNLOCK
##########
 
## REWRITE DEFAULTS ###
RewriteEngine On
RewriteBase /
 
## REQUIRE SUBDOMAIN ###
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^subdomain\.domain\.tld$ [NC]
RewriteRule ^/(.*)$ http://subdomain.domain.tld/$1 [L,R=301]
 
## SEO REWRITES ###
RewriteRule ^(.*)/ve/(.*)$    $1/voluntary-employee/$2 [L,R=301]
RewriteRule ^(.*)/hsa/(.*)$     $1/health-saving-account/$2 [L,R=301]
 
## WORDPRESS ###
RewriteCond %{REQUEST_FILENAME} !-f    # Existing File
RewriteCond %{REQUEST_FILENAME} !-d    # Existing Directory
RewriteRule . /index.php [L]
 
## ALTERNATIVE ANTI-HOTLINKING ###
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(subdomain\.)?domain.tld/.*$ [NC]
RewriteRule ^.*\.(bmp|tif|gif|jpg|jpeg|jpe|png)$ - [F]
 
## REDIRECT HOTLINKERS ###
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(subdomain\.)?domain.tld/.*$ [NC]
RewriteRule ^.*\.(bmp|tif|gif|jpg|jpeg|jpe|png)$ http://google.com [R]
 
## DENY REQUEST BASED ON REQUEST METHOD ###
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK|OPTIONS|HEAD)$ [NC]
RewriteRule ^.*$ - [F]
 
## REDIRECT UPLOADS ###
RewriteCond %{REQUEST_METHOD} ^(PUT|POST)$ [NC]
RewriteRule ^(.*)$ /cgi-bin/form-upload-processor.cgi?p=$1 [L,QSA]
 
## REQUIRE SSL EVEN WHEN MOD_SSL IS NOT LOADED ###
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]
 
### ALTERNATATIVE TO USING ERRORDOCUMENT ###
-> http://www.htaccesselite.com/d/htaccess-errordocument-examples-vt11.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /error.php [L]
 
## SEO REDIRECTS ###
Redirect 301 /2006/oldfile.html http://subdomain.domain.tld/newfile.html
RedirectMatch 301 /o/(.*)$ http://subdomain.domain.tld/s/dl/$1
 
=============================================================================#
          AUTHENTICATION AND SECURITY
=============================================================================#
 http://www.htaccesselite.com/basic-authentication-example-vt17.html
 
 Require (user|group|valid-user) (username|groupname)
##########
 
## BASIC PASSWORD PROTECTION ###
AuthType basic
AuthName "prompt"
AuthUserFile /.htpasswd
AuthGroupFile /dev/null
Require valid-user
 
## ALLOW FROM IP OR VALID PASSWORD ###
Require valid-user
Allow from 192.168.1.23
Satisfy Any
 
## PROTECT FILES ###
<filesMatch "\.(htaccess|htpasswd|ini|phps|fla|psd|log|sh)$">
  Order Allow,Deny
  Deny from all
</filesMatch>
 
## PREVENT HOTLINKING ###
SetEnvIfNoCase Referer "^http://subdomain.domain.tld/" good
SetEnvIfNoCase Referer "^$" good
<filesMatch "\.(png|jpg|jpeg|gif|bmp|swf|flv)$">
   Order Deny,Allow
   Deny from all
   Allow from env=good
   ErrorDocument 403 http://www.google.com/intl/en_ALL/images/logo.gif
   ErrorDocument 403 /images/you_bad_hotlinker.gif
</filesMatch>
 
## LIMIT UPLOAD FILE SIZE TO PROTECT AGAINST DOS ATTACK ###
LimitRequestBody 10240000 #bytes, 0-2147483647(2GB)
 
=============================================================================#
          SSL SECURITY
=============================================================================#
-> http://www.askapache.com/htaccess/ssl-example-usage-in-htaccess.html
##########
 
## MOST SECURE WAY TO REQUIRE SSL ###
-> http://www.askapache.com/htaccess/apache-ssl-in-htaccess-examples.html
SSLOptions +StrictRequire
SSLRequireSSL
SSLRequire %{HTTP_HOST} eq "domain.tld"
ErrorDocument 403 https://domain.tld
 
=============================================================================#
          SITE UNDER CONSTRUCTION
=============================================================================#
 Heres some awesome htaccess to use when you are developing a site
##########
 
## COMBINED DEVELOPER HTACCESS CODE-USE THIS ###
<filesMatch "\.(flv|gif|jpg|jpeg|png|ico|js|css|pdf|swf|html|htm|txt)$">
   Header set Cache-Control "max-age=5"
</filesMatch>
AuthType basic
AuthName "Ooops! Temporarily Under Construction..."
AuthUserFile /.htpasswd
AuthGroupFile /dev/null
Require valid-user           # password prompt for everyone else
Order Deny,Allow
Deny from all
Allow from 192.168.64.5      # Your, the developers IP address
Allow from w3.org            # css/xhtml check jigsaw.w3.org/css-validator/
Allow from googlebot.com     # Allows google to crawl your pages
Satisfy Any                  # no password required if host/ip is Allowed
 
## DONT HAVE TO EMPTY CACHE OR RELOAD TO SEE CHANGES ###
ExpiresDefault A5 #If using mod_expires
<filesMatch "\.(flv|gif|jpg|jpeg|png|ico|js|css|pdf|swf|html|htm|txt)$">
   Header set Cache-Control "max-age=5"
</filesMatch>
 
## ALLOW ACCESS WITH PASSWORD OR NO PASSWORD FOR SPECIFIC IP/HOSTS ###
AuthType basic
AuthName "Ooops! Temporarily Under Construction..."
AuthUserFile /.htpasswd
AuthGroupFile /dev/null
Require valid-user           # password prompt for everyone else
Order Deny,Allow
Deny from all
Allow from 192.168.64.5      # Your, the developers IP address
Allow from w3.org            # css/xhtml check jigsaw.w3.org/css-validator/
Allow from googlebot.com     # Allows google to crawl your pages
Satisfy Any                  # no password required if host/ip is Allowed

How To Use .htaccess 301 Redirect

Using .htaccess to redirect your visitors from one page to another is the cleanest fastest way of making a redirect. This is the same method I use to redirect readers of this blog from DavePit.com to DavidPitlyuk.com. I do this because DavidPitlyuk.com may be too hard to spell, so I added DavePit.com which is easy, and added a simple re-direct to move the readers over to the correct domain.

You can use .htaccess to redirect entire domains, folders, specific files, and more. John Chow uses an .htaccess redirect to set his preferred domain, something that can better your site from an SEO standpoint. I’ll go over how to do this as well.

Things To Note

Keep in mind that .htaccess is only supported on non-Windows servers, so any of you guys using Windows need to utilize another method to redirect your users. Also, if you are creating the .htaccess file in Windows, you’ll find that it doesn’t like filenames with no name on it. The workaround for this is to make the file something like htaccess.txt, and after uploading the file, rename on the server. Make sure to change http://www.example.com to your own domain name in any of the examples.

So let’s go over a few common methods of using the redirect:

Redirect An Entire Domain

This is what I use to redirect everybody who accesses this site at DavePit.com and transfer them to DavidPitlyuk.com.

Redirect 301 / http://www.example.com/

Redirect non-WWW to WWW (example.com > www.example.com)

This is the setting the preferred domain that I was talking about earlier. It will redirect all of your traffic at the example.com level and transfer it to www.example.com

Options +FollowSymLinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^example.com [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]

Redirect A Single File Or Folder

This will be used if you want to redirect something like http://www.example.com/blog2 to http://www.example.com/blog or http://www.example.com/blog.php to http://www.example.com/blog.

Redirect 301 /OldPageOrDirectory.html http://www.example.com/NewPageOrDirectory.html

There are many other methods of using .htaccess to redirect, but in the most cases this will cover what you need.

How to use .htaccess

introduction to .htaccess

There’s a good reason why you won’t see .htaccess files on the web; almost every web server in the world is configured to ignore them, by default. Same goes for most operating systems. Mainly it’s the dot “.” at the start, you see?

If you don’t see, you’ll need to disable your operating system’s invisible file functions, or use a text editor that allows you to open hidden files, something like bbedit on the Mac platform. On windows, showing invisibles in explorer should allow any text editor to open them, and most decent editors to save them too**. Linux dudes know how to find them without any help from me.
Mac Finder view with invisible files
that same folder, as seen from Mac OS X

In both images, the operating system has been instructed to display invisible files. ugly, but necessary sometimes. You will also need to instruct your ftp client to do the same.

By the way; the windows screencap is more recent than the mac one, moved files are likely being handled by my clever 404 script.

** even notepad can save files beginning with a dot, if you put double-quotes around the name when you save it; i.e.. “.htaccess”. You can also use your ftp client to rename files beginning with a dot, even on your local filesystem; works great in FileZilla.

What are .htaccess files anyway?
Simply put, they are invisible plain text files where one can store server directives. Server directives are anything you might put in an Apache config file (httpd.conf) or even a php.ini**, but unlike those “master” directive files, these .htaccess directives apply only to the folder in which the .htaccess file resides, and all the folders inside.

This ability to plant .htaccess files in any directory of our site allows us to set up a finely-grained tree of server directives, each subfolder inheriting properties from its parent, whilst at the same time adding to, or over-riding certain directives with its own .htaccess file. For instance, you could use .htacces to enable indexes all over your site, and then deny indexing in only certain subdirectories, or deny index listings site-wide, and allow indexing in certain subdirectories. One line in the .htaccess file in your root and your whole site is altered. From here on, I’ll probably refer to the main .htaccess in the root of your website as “the master .htaccess file”, or “main” .htaccess file.

There’s a small performance penalty for all this .htaccess file checking, but not noticeable, and you’ll find most of the time it’s just on and there’s nothing you can do about it anyway, so let’s make the most of it..

** Your main php.ini, that is, unless you are running under phpsuexec, in which case the directives would go inside individual php.ini files

What can I do with .htaccess files?
Almost any directive that you can put inside an httpd.conf file will also function perfectly inside an .htaccess file. Unsurprisingly, the most common use of .htaccess is to..

control access
.htaccess is most often used to restrict or deny access to individual files and folders. A typical example would be an “includes” folder. Your site’s pages can call these included scripts all they like, but you don’t want users accessing these files directly. In that case you would drop an .htaccess file in the includes folder with content something like this..

NO ENTRY!
# no one gets in here!
deny from all

which would deny ALL direct access to ANY files in that folder. You can be more specific with your conditions, for instance limiting access to a particular IP range, here’s a handy top-level rule for a local test server..

NO ENTRY outside of the LAN!
# no nasty crackers in here!
order deny,allow
deny from all
allow from 192.168.0.0/24
# this would do the same thing..
#allow from 192.168.0

Generally these sorts of requests would bounce off your firewall anyway, but on a live server (like my dev mirror sometimes is) they become useful for filtering out undesirable IP blocks, known risks, lots of things. By the way, in case you hadn’t spotted; lines beginning with “#” are ignored by Apache; handy for comments.

Sometimes, you will only want to ban one IP, perhaps some persistent robot that doesn’t play by the rules..

post user agent every fifth request only. hmmm. ban IP..
# someone else giving the ruskies a bad name..
order allow,deny
deny from 83.222.23.219
allow from all

The usual rules for IP addresses apply, so you can use partial matches, ranges, and so on. Whatever, the user gets a 403 “access denied” error page in their client software (browser, usually), which certainly gets the message across. This is probably fine for most situations, but in part two I’ll demonstrate some cooler ways to deny access.

custom error documents
I guess I should briefly mention that .htaccess is where most folk configure their error documents. Usually with sommething like this..

the usual method. the “err” folder (with the custom pages) is in the root
# custom error documents
ErrorDocument 401 /err/401.php
ErrorDocument 403 /err/403.php
ErrorDocument 404 /err/404.php
ErrorDocument 500 /err/500.php

You can also specify external URLs, though this can be problematic, and is best avoided. One quick and simple method is to specify the text in the directive itself, you can even use HTML (though there is probably a limit to how much HTML you can squeeze onto one line). Remember to begin with a “, but DO NOT end with one.

measure twice, quote once..
# quick custom error “document”..
NO! ErrorDocument 404 “
There is nothing here.. go away quickly!

Using a custom error document is a Very Good Idea, and will give you a second chance at your almost-lost visitors. I recommend you download mine. But then, I would.

password protected directories
The next most obvious use for our .htaccess files is to allow access to only specific users, or user groups, in other words; password protected folders. a simple authorisation mechanism might look something like this..

a simple sample .htaccess file for password protection:
AuthType Basic
AuthName “restricted area”
AuthUserFile /usr/local/var/www/html/.htpasses
require valid-user

You can use this same mechanism to limit only certain kinds of requests, too..

only valid users can POST in here, anyone can GET, PUT, etc:
AuthType Basic
AuthName “restricted area”
AuthUserFile /usr/local/var/www/html/.htpasses

require valid-user

You can find loads of online examples of how to setup authorization using .htaccess, and so long as you have a real user (or create one, in this case, ‘jimmy’) with a real password (you will be prompted for this, twice) in a real password file (the -c switch will create it)..

htpasswd -c /usr/local/var/www/html/.htpasses jimmy

..the above will work just fine. htpasswd is a tool that comes free with Apache, specifically for making and updating password files, check it out. The windows version is the same; only the file path needs to be changed; to wherever you want to put the password file.

Note: if the Apache bin/ folder isn’t in your PATH, you will need to cd into that directory before performing the command. Also note: You can use forward and back-slashes interchangeably with Apache/php on Windows, so this would work just fine..

htpasswd -c c:/unix/usr/local/Apache2/conf/.htpasses jimmy

Relative paths are fine too; assuming you were inside the bin/ directory of our fictional Apache install, the following would do exactly the same as the above..

htpasswd -c ../conf/.htpasses jimmy

Naming the password file .htpasses is a habit from when I had to keep that file inside the web site itself, and as web servers are configured to ignore files beginning with .ht, they too, remain hidden. If you keep your password file outside the web root (a better idea), then you can call it whatever you like, but the .ht_something habit is a good one to keep, even inside the web tree, it is secure enough for our basic purpose..

Once they are logged in, you can access the remote_user environmental variable, and do stuff with it..

the remote_user variable is now available..
RewriteEngine on
RewriteCond %{remote_user} !^$ [nc]
RewriteRule ^(.*)$ /users/%{remote_user}/$1

Which is a handy directive, utilizing mod_rewrite; a subject I delve into far more deeply, in part two.

get better protection..
The authentication examples above assume that your web server supports “Basic” http authorisation, as far as I know they all do (it’s in the Apache core). Trouble is, some browsers aren’t sending password this way any more, personally I’m looking to php to cover my authorization needs. Basic auth works okay though, even if it isn’t actually very secure - your password travels in plain text over the wire, not clever.

If you have php, and are looking for a more secure login facility, check out pajamas. It’s free. If you are looking for a password-protected download facility (and much more, besides), check out my distro machine, also free.

500 error
If you add something that the server doesn’t understand or support, you will get a 500 error page, aka.. “the server did a boo-boo”. Even directives that work perfectly on your test server at home may fail dramatically at your real site. In fact this is a great way to find out if .htaccess files are enabled on your site; create one, put some gibberish in it, and load a page in that folder, wait for the 500 error. if there isn’t one, probably they are not enabled.

If they are, we need a way to safely do live-testing without bringing the whole site to a 500 standstill.

Fortunately, in much the same way as we used the
tag above, we can create conditional directives, things which will only come into effect if certain conditions are true. The most useful of these is the “ifModule” condition, which goes something like this..

only if PHP is loaded, will this directive have any effect

php_value default_charset utf-8

..which placed in your master .htaccess file, that would set the default character encoding of your entire site to utf-8 (a good idea!), at least, anything output by PHP. If the PHP4 module isn’t running on the server, the above .htaccess directive will do exactly nothing; Apache just ignores it. As well as proofing us against knocking the server into 500 mode, this also makes our .htaccess directives that wee bit more portable. Of course, if your syntax is messed-up, no amount of if-module-ing is going to prevent a error of some kind, all the more reason to practice this stuff on a local test server.

groovy things to do with .htaccess
So far we’ve only scratched the surface. aside from authorisation, the humble .htaccess file can be put to all kinds of uses. If you’ve ever had a look in my public archives you will have noticed that that the directories are fully browsable, just like in the old days before adult web hosts realized how to turn that feature off! a line like this..

bring back the directories!
Options +Indexes +MultiViews +FollowSymlinks

will almost certainly turn it back on again. And if you have mod_autoindex.c installed on your server (probably, yes), you can get nice fancy indexing, too..

show me those files!

IndexOptions FancyIndexing

..which, as well as being neater, allows users to click the titles and, for instance, order the listing by date, or file size, or whatever. It’s all for free too, built-in to the server, we’re just switching it on. You can control certain parameters too..

let’s go all the way!

IndexOptions FancyIndexing IconHeight=16 IconWidth=16

Other parameters you could add include..

NameWidth=30
DescriptionWidth=30
IconsAreLinks SuppressHTMLPreamble (handy!)

I’m not mentioning the “XHTML” parameter in Apache2, because it still isn’t! Anyways, I’ve chucked one of my old fancy indexing .htaccess file onsite for you to have some fun with. Just add readme.html and away you go! note: these days I use a single header files for all the indexes, and only drop in local “readme” files. Check out the example, and my public archives for more details.

custom directory index files
While I’m here, it’s worth mentioning that .htaccess is where you can specify which files you want to use as your indexes, that is, if a user requests /foo/, Apache will serve up /foo/index.html, or whatever file you specify.

You can also specify multiple files, and Apache will look for each in order, and present the first one it finds. It’s generally setup something like..

DirectoryIndex index.html index.php index.htm

It really is worth scouting around the Apache documentation, often you will find controls for things you imagined were uncontrollable, thereby creating new possibilities, better options for your website. My experience of the magic “LAMP” (Linux-Apache-MySQL-PHP) has been.. “If you can imagine that it can be done, it can be done”. Swap “Linux” for any decent operating system, the “AMP” part runs on most of them.

Okay, so now we have nice fancy directories, and some of them password protected, if you don’t watch out, you’re site will get popular, and that means bandwidth..

save bandwidth with .htaccess!
If you pay for your bandwidth, this wee line could save you hard cash..

save me hard cash! and help the internet!

php_value zlib.output_compression 16386

All it does is enables PHP’s built-in transparent zlib compression. This will half your bandwidth usage in one stroke, more than that, in fact. Of course it only works with data being output by the PHP module, but if you design your pages with this in mind, you can use php echo statements, or better yet, php “includes” for your plain html output and just compress everything! Remember, if you run phpsuexec, you’ll need to put php directives in a local php.ini file, not .htaccess. See here for more details.

hide and deny files
Do you remember I mentioned that any file beginning with .ht is invisible? ..”almost every web server in the world is configured to ignore them, by default” and that is, of course, because .ht_anything files generally have server directives and passwords and stuff in them, most servers will have something like this in their main configuration..

Standard setting..

Order allow,deny
Deny from all
Satisfy All

which instructs the server to deny access to any file beginning with .ht, effectively protecting our .htaccess and other files. The “.” at the start prevents them being displayed in an index, and the .ht prevents them being accessed. This version..

ignore what you want

Order allow,deny
Deny from all
Satisfy All

tells the server to deny access to *.log files. You can insert multiple file types into each rule, separating them with a pipe “|”, and you can insert multiple blocks into your .htaccess file, too. I find it convenient to put all the files starting with a dot into one, and the files with denied extensions into another, something like this..

the whole lot
# deny all .htaccess, .DS_Store $hî†Ã© and ._* (resource fork) files

Order allow,deny
Deny from all
Satisfy All

# deny access to all .log and .comment files

Order allow,deny
Deny from all
Satisfy All

would cover all ._* resource fork files, .DS_Store files (which the Mac Finder creates all over the place) *.log files, *.comment files and of course, our .ht* files. You can add whatever file types you need to protect from direct access. I think it’s clear now why the file is called “.htaccess”.
These days, using is preferred over , mainly because you can use regular expression in the conditions (very handy), produce clean, more readable code. Here’s an example. which I use for my php-generated style sheets..

parse file.css and file.style with the php machine..
# handler for phpsuexec..

SetHandler application/x-httpd-php

Any files matching the regular expression statement, that is files with a *.css or *.style extension, will now be handled by php, rather than simply served up by Apache. Any statements you come across can be advantageously replaced by statements. Good to know.

Tips and Examples for how to use your .htaccess file

.htaccess file explained with examples for eliminating referrer spam and deep linking

Someone recently asked how to block a particular IP address from their
web site. the .htaccess file is a good way to do this. I’m assuming
that you can google for information about where to put your .htaccess
file, and am only going to address some ways to populate your .htaccess
file to accomplish some routine access control and URL rewriting.

For more information on URL rewriting do a google search for:
+mod_rewrite +documentation
or
+mod_rewrite +examples

Topics covered are:


* A brief introduction to Regular Expressions
* Denying access based on IP address of browser
* Denying access based on HTTP_REFERER
* Denying linking or deep linking of images on your site
* Sending naughty users to “good” content elsewhere on the web
* Rewriting URLs in order to remedy an incorrect URL posting to email lists

The statements or directives that are used in my .htaccess file are what are known as "regular expressions". This site seems to be comprehensive, and was at the top of the google search for "regular expressions".

Here are a couple of quick explanations for what's being done in my .htaccess file.

* ^ refers to the beginning of a string. So any regex that has ^ in it means "starts with"
* $ refers to the end of the string. So any regex that ends with $ means "ends with" the previous character
* ! is negation. Anywhere you see a ! (aka "bang"), it means not. so !string, matches everything except string
* . means any single character
* * means one of more of the preceding character. Hence .* is like the UNIX or DOS * wildcard
* | is a logical OR. I explain more about it below.
* \ escapes the "special characters" just described. So if I wanted to match a . I would write the regex \.

So to put a couple of these together:

* ^$ refers to a string that starts and stops with nothing in between, also known as an empty string, as there's nothing in it.
* ^stevem.* refers to a string that starts with stevem and then may contain any number of any characters.
* ^shooter\.net$ refers to a string that contains only "shooter.net"

I describe how I've setup these regexs below using the characters described above...

Use Google for more info.

Another thing to note: In a couple of the directives in my .htaccess file I block some rather large chunks of the Internet from getting to my web site. I'm doing this because I want to be sure that I've blocked irritating (usually referrer spammers -- SCUM) from hitting my site and I've used a whois server to find out what the netblock boundaries are, and blocked the entire netblock. I also keep a close eye on my access log to see who is being denied access to my site. I strongly suggest that if you don't know what you're doing, don't take such extreme measures, and instead block complete single IP addresses instead of networks.

And most of all, be careful and make sure you understand what you are doing in your .htaccess file. Then TEST TEST TEST to make sure it's accomplishing what you want and that you haven't crippled your site.

.htaccess files are powerful tools for fine tuning access to your web site. To paraphrase a famouse comic book uncle, "With great power comes the ablity to really screw things up."

Here is a copy of my .htaccess file with inline comments attempting to describe what I'm doing.

## The next several statements set a variable, (BadAgent, BadReferer, BadAddy)
## if the condition is met. the three deny lines below cause the
## 403 Denied to be issued

## This identifies a couple of irritating User-Agents
SetEnvIfNoCase User-Agent ".*(AdultGods|php/perl).*" BadAgent

## This identifies a couple irritating Referers
SetEnvIfNoCase Referer ".*(x-stories|plattendreher|pureteen|stormfront).*" BadReferer

## This blocks some IP addresses that I don't like this is a rather complex regular expression
## the () symbols contain a group of expressions separated by the pipe symbol |
## the | acts as a logical OR.
## so for example, we match a string that contains one or more of any character: .*
## that contains one of those three IP addresses listed in the ()s
## and then can be followed by one or more of any (or none at all) characaters.
## Do some searching on google if you really want to dig this deeply into regexs
##
SetEnvIfNoCase REMOTE_ADDR ".*(193.194.84.1|69.31.86.133|205.252.49.146).*" BadAddy

## This blocks an entire class B... It's all owned by one ISP, and the
## referrer spam was coming from a dozen or more networks contained in this netblock
SetEnvIfNoCase REMOTE_ADDR "66.154.*" BadAddy

## This blocks two class B networks. Same story as above. However,
## the \. included below makes sure that we only block two networks
## 198.25.0.0 and 198.26.0.0 if we had left out the .\ we would have matched
## HUNDREDS of networks, like 198.251.0.0 and 198.268.0.0 etc...
##
SetEnvIfNoCase REMOTE_ADDR "198.2(5|6)\..*" BadAddy

## Here's where we setup the denials if there were matches above
order deny,allow
deny from env=BadAgent
deny from env=BadReferer
deny from env=BadAddy


## This part of the .htaccess file is where I do some URL rewriting


## Gotta turn on the engine if we're going to get anywhere
RewriteEngine on

## These two rules cause requests for atom and rss requests to the
## docroot of my site to be rewritten to use ExpressionEngine system
## so they are properly served
##
RewriteRule .*atom.xml$ http://www.shooter.net/index.php/weblog/rss_atom/ [R]
RewriteRule .*rss.xml$ http://www.shooter.net/index.php/weblog/rss_2.0/ [R]

## This commented out rule causes all requests for index.html to be
## rewritten to use ExpressionEngine. It was in place as I was migrating
## and I wanted everything directed into EE instead of using my old static pages.
##
#RewriteRule /.*index.html$ http://www.shooter.net/index.php [R]

## I posted an email to a mailing list announcing this article, but I
## somehow managed to screw it up. This entry fixes it so I didn't
## have to post an "I'm a dummy" followup
## see if you can figure out the incorrect URL that I posted
##
RewriteRule ^using-a-polarizer/ http://www.shooter.net/index.php/weblog/Item/using-a-polarizer/ [R]


## This is how I prevent other sites from linking to my images, a practice
## also known as "deep linking". It pisses me off that in spite of my
## copyright notice, forbidding this practice, some people think it's okay
## to steal my work, and steal my bandwidth too...
##
##
## This line says, only match if the HTTP_REFERER environment variable is
## not empty otherwise fall out of this series of conditionals. So if
## there is no HTTP_REFERER set, we drop out of this set of conditionals,
## which means that we don't execute the RewriteRule at the end of this
## block of conditionals.
##
RewriteCond %{HTTP_REFERER} !^$

## This is a case insensitive (because of the [NC] flag) expression
## that causes any referrals from shooter.net to exits from this series
## of conditionals
##
RewriteCond %{HTTP_REFERER} !.*shooter.net.* [NC]

## dicelady.com is my mom's web site. Since we're sharing the installation
## of ExpressionEngine, I want to serve images for her... So if the
## HTTP_REFERER is not from her site we stay in this series of
## conditionals, if it is from her site, the request drops out of this
## series of conditionals,
##
RewriteCond %{HTTP_REFERER} !^http://www.dicelady.com/.*$ [NC]

## Here's the action item. If we have a referrer, and it's not from
## shooter.net or dicelady.com and the request ends in jpg, then no matter
## what image they requested, we're going to serve them up a gif file that
## is a reminder to not steal my images...
##
RewriteRule .*\.jpg$ http://shooter.net/ah.ha.1.gif [R]

## The website name has been changed to prevent the guilty
## from knowing how I did what I did...
##
## This one is kinda fun. There is a website whose domain
## name contains "hatemongersite". They are a white supremecist
## website that was linking to my images of same-sex weddings.
## And saying derogatory ugly things about the people that I
## took pictures of... So, ANY request for ANYTHING from my
## site that originates from this website, gets redirected to
## a TOLERANCE site, and is served a nice pdf pamphlet about
## "promoting tolerance" The nice thing about sending them a
## pdf is most web browsers will launch a help app, adobe acrobat
## to display the pdf... So they are browsing along, and suddenly they
## have a "promoting tolerance" pdf being displayed...
##
RewriteCond %{HTTP_REFERER} ^http://.*hatemongersite.*$ [NC]
RewriteRule .* http://www.tolerance.org/101_tools/101_tools.pdf [R]

## This one is simple. Requests from a site the irritated me
## are rewritten to send them to a site with a very large pipe
## and an 8mb thermal image of tokyo!
##
RewriteCond %{HTTP_REFERER} ^http://.*popmiranda.*$ [NC]
RewriteRule .* http://vvvvvvv.vv.vvv.vvv/gallery/images/tokyo.jpg [R]

## Here's how you can redirect traffic from a certain address or range
## of addresses to another site... This was the network that included
## several users from the hatemongersite (IP changed to protect the guilty)
## I point them at the "promoting tolerance" pdf.
##
RewriteCond %{REMOTE_ADDR} 192.168.10.*
RewriteRule .*\.html$ http://www.tolerance.org/101_tools/101_tools.pdf [R]


So that's about it... I hope you've enjoyed this little jaunt through my .htaccess file.

Others htaccess Trick

The Apache Web server provides a feature called .htaccess file, which provides commands to control a Web site. This file is simply a text file containing Apache directives. Those directives apply to the documents in the directory where the file is located, and to all subdirectories under it as well. Other .htaccess files in subdirectories may change or nullify the effects of those in parent directories.

You have to be careful when editing .htaccess files, as a small mistake can make your Web site stop working. You should immediately test the site to be sure it works.

You can use any text editor to create or make changes to .htaccess files. Keep in mind that commands in these files should be placed on one line only, so if your text editor uses word-wrap, make sure it's disabled. Be sure .htaccess file is uploaded in ASCII mode, not BINARY, or it won't work.

Your text editor or operating system may probably not allow to save file as .htaccess. The solution is to save the file as htaccess.txt and upload it to your server. After doing that, you should use your FTP client and rename the file to it's proper name.

Some sites do not allow use of .htaccess files, since they can slow down a server overloaded with domains if they're all using such files, and some things that they can do can compromise a server configuration that has been specifically setup by the admin. Just be sure to read their TOS carefully or ask permission from your host.

Here are the most notable and useful .htaccess examples...
Custom error pages

The most common errors are 404 (Not Found) and 500 (Internal Server Error). Design your custom Web pages for these errors (you aren't limited to these errors, you can create an error page for each and every error). Add the following commands to your .htaccess file...
ErrorDocument 404 /404.html
ErrorDocument 500 /500.html

You can name the pages anything you want, and you can place them anywhere you want within your site. The initial slash in the directory location represents the root directory of your site.
Enabling SSI

If you want to use SSI, but can't do so with your current Web host, you can change that with .htaccess file. The following lines tell the server that any file named .shtml should be parsed for server side commands...
AddType text/html .shtml
AddHandler server-parsed .shtml
Options Indexes FollowSymLinks Includes

If you don't care about the performance hit of having all .html files parsed for SSI, change the second line to...
AddHandler server-parsed .shtml .html

If you're going to keep SSI pages with the extension of .shtml, and you want to use SSI on your index pages, you need to add the following line to your .htaccess file...
DirectoryIndex index.shtml index.html

This allows a page named index.shtml to be your default page, and if that isn't found, index.html is loaded.
Redirects

You can use .htaccess file to redirect any request for a specific page to a new page...
Redirect /OldDir/old.html http://site.com/NewDir/new.html

Server-side redirects are very useful for shortening affiliate links. Your visitors won't be turned off by long links that are obviously affiliate links. For example, to create a redirect at the URL:
http://YourSite.com/link
to point to the URL:
http://www.MerchantDomain.com/affil.cgi?12345
put this line in your .htaccess file...
Redirect /link http://www.MerchantDomain.com/affil.cgi?12345
Protecting your bandwidth

"Bandwidth stealing," also known as "hot linking," is linking directly to non-html objects on another server, such as images, electronic books etc. The most common practice of hot linking pertains to another site's images.

To disallow hot linking on your server, create the following .htaccess file and upload it to the folder that contains the images you wish to protect...
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?YourSite\.com/.*$ [NC]
RewriteRule \.(gif|jpg)$ - [F]

Replace "YourSite.com" with your own. The above code causes a broken image to be displayed when it's hot linked. If you'd like to display an alternate image in place of the hot linked one, replace the last line with...
RewriteRule \.(gif|jpg)$ http://www.YourSite.com/stop.gif [R,L]

Replace "YourSite.com" and stop.gif with your real names.
Preventing directory listing

Typically servers are setup to prevent directory listing, but often they aren't. If you have a directory full of downloads or images that you don't want people to be able to browse through, add the following line to your .htaccess file...
IndexIgnore *

The * matches all files. If, for example, you want to prevent only listing of images, use...
IndexIgnore *.gif *.jpg
Redirecting YourSite.com to www.YourSite.com

If search engines find both www and non-www links from other sites to your site, they may treat http://YourSite.com and http://www.YourSite.com as two different websites with the same content. This means that your site can be penalized for duplicate content.

Many experts recommend to set up a 301 redirect (permanent redirect) from YourSite.com to www.YourSite.com...
RewriteEngine On
RewriteCond %{HTTP_HOST} ^YourSite\.com [nc]
RewriteRule (.*) http://www.YourSite.com/$1 [R=301,L]

Replace "YourSite.com" with your real domain name.

Superb htaccess Tricks

General Information

.htaccess Definition1

Apache server software provides distributed (i.e., directory-level) configuration via Hypertext Access files. These .htaccess files enable the localized fine-tuning of Apache’s universal system-configuration directives, which are defined in Apache’s main configuration file. The localized .htaccess directives must operate from within a file named .htaccess. The user must have appropriate file permissions to access and/or edit the .htaccess file. Further, .htaccess file permissions should never allow world write access — a secure permissions setting is “644”, which allows universal read access and user-only write access. Finally, .htaccess rules apply to the parent directory and all subdirectories. Thus to apply configuration rules to an entire website, place the .htaccess file in the root directory of the site.

Commenting .htaccess Code

Comments are essential to maintaining control over any involved portion of code. Comments in .htaccess code are fashioned on a per-line basis, with each line of comments beginning with a pound sign #. Thus, comments spanning multiple lines in the .htaccess file require multiple pound signs. Further, due to the extremely volatile nature of htaccess voodoo, it is wise to include only alphanumeric characters (and perhaps a few dashes and underscores) in any .htaccess comments.

Important Notes for .htaccess Noobs

As a configuration file, .htaccess is very powerful. Even the slightest syntax error (like a missing space) can result in severe server malfunction. Thus it is crucial to make backup copies of everything related to your site (including any original .htaccess files) before working with your Hypertext Access file(s). It is also important to check your entire website thoroughly after making any changes to your .htaccess file. If any errors or other problems are encountered, employ your backups immediately to restore original functionality.

Performance Issues

.htaccess directives provide directory-level configuration without requiring access to Apache’s main server cofiguration file (httpd.conf). However, due to performance and security concerns, the main configuration file should always be used for server directives whenever possible. For example, when a server is configured to process .htaccess directives, Apache must search every directory within the domain and load any and all .htaccess files upon every document request. This results in increased page processing time and thus decreases performance. Such a performance hit may be unnoticeable for sites with light traffic, but becomes a more serious issue for more popular websites. Therefore, .htaccess files should only be used when the main server configuration file is inaccessible. See the “Performance Tricks” section of this article for more information.

Regex Character Definitions for htaccess2

#
the # instructs the server to ignore the line. used for including comments. each line of comments requires it’s own #. when including comments, it is good practice to use only letters, numbers, dashes, and underscores. this practice will help eliminate/avoid potential server parsing errors.
[F]
Forbidden: instructs the server to return a 403 Forbidden to the client.
[L]
Last rule: instructs the server to stop rewriting after the preceding directive is processed.
[N]
Next: instructs Apache to rerun the rewrite rule until all rewriting directives have been achieved.
[G]
Gone: instructs the server to deliver Gone (no longer exists) status message.
[P]
Proxy: instructs server to handle requests by mod_proxy
[C]
Chain: instructs server to chain the current rule with the previous rule.
[R]
Redirect: instructs Apache to issue a redirect, causing the browser to request the rewritten/modified URL.
[NC]
No Case: defines any associated argument as case-insensitive. i.e., "NC" = "No Case".
[PT]
Pass Through: instructs mod_rewrite to pass the rewritten URL back to Apache for further processing.
[OR]
Or: specifies a logical "or" that ties two expressions together such that either one proving true will cause the associated rule to be applied.
[NE]
No Escape: instructs the server to parse output without escaping characters.
[NS]
No Subrequest: instructs the server to skip the directive if internal sub-request.
[QSA]
Append Query String: directs server to add the query string to the end of the expression (URL).
[S=x]
Skip: instructs the server to skip the next "x" number of rules if a match is detected.
[E=variable:value]
Environmental Variable: instructs the server to set the environmental variable "variable" to "value".
[T=MIME-type]
Mime Type: declares the mime type of the target resource.
[]
specifies a character class, in which any character within the brackets will be a match. e.g., [xyz] will match either an x, y, or z.
[]+
character class in which any combination of items within the brackets will be a match. e.g., [xyz]+ will match any number of x’s, y’s, z’s, or any combination of these characters.
[^]
specifies not within a character class. e.g., [^xyz] will match any character that is neither x, y, nor z.
[a-z]
a dash (-) between two characters within a character class ([]) denotes the range of characters between them. e.g., [a-zA-Z] matches all lowercase and uppercase letters from a to z.
a{n}
specifies an exact number, n, of the preceding character. e.g., x{3} matches exactly three x’s.
a{n,}
specifies n or more of the preceding character. e.g., x{3,} matches three or more x’s.
a{n,m}
specifies a range of numbers, between n and m, of the preceding character. e.g., x{3,7} matches three, four, five, six, or seven x’s.
()
used to group characters together, thereby considering them as a single unit. e.g., (perishable)?press will match press, with or without the perishable prefix.
^
denotes the beginning of a regex (regex = regular expression) test string. i.e., begin argument with the proceeding character.
$
denotes the end of a regex (regex = regular expression) test string. i.e., end argument with the previous character.
?
declares as optional the preceding character. e.g., monzas? will match monza or monzas, while mon(za)? will match either mon or monza. i.e., x? matches zero or one of x.
!
declares negation. e.g., “!string” matches everything except “string”.
.
a dot (or period) indicates any single arbitrary character.
-
instructs “not to” rewrite the URL, as in “...domain.com.* - [F]”.
+
matches one or more of the preceding character. e.g., G+ matches one or more G’s, while "+" will match one or more characters of any kind.
*
matches zero or more of the preceding character. e.g., use “.*” as a wildcard.
|
declares a logical “or” operator. for example, (x|y) matches x or y.
\
escapes special characters ( ^ $ ! . * | ). e.g., use “\.” to indicate/escape a literal dot.
\.
indicates a literal dot (escaped).
/*
zero or more slashes.
.*
zero or more arbitrary characters.
^$
defines an empty string.
^.*$
the standard pattern for matching everything.
[^/.]
defines one character that is neither a slash nor a dot.
[^/.]+
defines any number of characters which contains neither slash nor dot.
http://
this is a literal statement — in this case, the literal character string, “http://”.
^domain.*
defines a string that begins with the term “domain”, which then may be proceeded by any number of any characters.
^domain\.com$
defines the exact string “domain.com”.
-d
tests if string is an existing directory
-f
tests if string is an existing file
-s
tests if file in test string has a non-zero value

Redirection Header Codes

* 301 - Moved Permanently
* 302 - Moved Temporarily
* 403 - Forbidden
* 404 - Not Found
* 410 - Gone

Essentials

Commenting your htaccess Files

It is an excellent idea to consistenly and logically comment your htaccess files. Any line in an htaccess file that begins with the pound sign ( # ) tells the server to ignore it. Multiple lines require multiple pounds and use letters/numbers/dash/underscore only:

# this is a comment
# each line must have its own pound sign
# use only alphanumeric characters along with dashes - and underscores _

Enable Basic Rewriting

Certain servers may not have “mod_rewrite” enabled by default. To ensure mod_rewrite (basic rewriting) is enabled throughout your site, add the following line once to your site’s root htaccess file:

# enable basic rewriting
RewriteEngine on

Enable Symbolic Links

Enable symbolic links (symlinks) by adding the following directive to the target directory’s htaccess file. Note: for the FollowSymLinks directive to function, AllowOverride Options privileges must be enabled from within the server configuration file (see proceeding paragraph for more information):

# enable symbolic links
Options +FollowSymLinks

Enable AllowOverride

For directives that require AllowOverride in order to function, such as FollowSymLinks (see above paragraph), the following directive must be added to the server configuration file. For performance considerations, it is important to only enable AllowOverride in the specific directory or directories in which it is required. In the following code chunk, we are enabling the AllowOverride privs only in the specified directory (/www/replace/this/with/actual/directory). Refer to this section for more information about AllowOverride and performance enhancement:

# enable allowoverride privileges

AllowOverride Options


Rename the htaccess File

Not every system enjoys the extension-only format of htaccess files. Fortunately, you can rename them to whatever you wish, granted the name is valid on your system. Note: This directive must be placed in the server-wide configuration file or it will not work:

# rename htaccess files
AccessFileName ht.access

Note: If you rename your htaccess files, remember to update any associated configuration settings. For example, if you are protecting your htaccess file via FilesMatch, remember to inform it of the renamed files:

# protect renamed htaccess files

Order deny,allow
Deny from all


Retain Rules Defined in httpd.conf

Save yourself time and effort by defining replicate rules for multiple virtual hosts once and only once via your httpd.conf file. Then, simply instruct your target htaccess file(s) to inheret the httpd.conf rules by including this directive:

RewriteOptions Inherit
Performance

Improving Performance via AllowOverride

Limit the extent to which htaccess files decrease performance by enabling AllowOverride only in required directories. For example, if AllowOverride is enabled throughout the entire site, the server must dig through every directory, searching for htaccess files that may not even exist. To prevent this, we disable the AllowOverride in the site’s root htaccess file and then enable AllowOverride only in required directories via the server config file (refer to this section for more information). Note: if you do not have access to your site’s server config file and also need AllowOverride privileges, do not use this directive:

# increase performance by disabling allowoverride
AllowOverride None

Improving Performance by Passing the Character Set

Prevent certain 500 error displays by passing the default character set parameter before you get there. Note: replace the “utf-8” below with the charset that your site is using:

# pass the default character set
AddDefaultCharset utf-8

Improving Performance by Preserving Bandwidth

To increase performance on PHP enabled servers, add the following directive:

# preserve bandwidth for PHP enabled servers

php_value zlib.output_compression 16386


Disable the Server Signature

Here we are disabling the digital signature that would otherwise identify the server:

# disable the server signature
ServerSignature Off

Set the Server Timezone

Here we are instructing the server to synchronize chronologically according to the time zone of some specified state:

# set the server timezone
SetEnv TZ America/Washington

Set the Email Address for the Server Administrator

Here we are specifying the default email address for the server administrator:

# set the server administrator email
SetEnv SERVER_ADMIN default@domain.com

Improve Site Transfer Speed by Enabling File Caching

The htaccess genius over at askapache.com explains how to dramatically improve your site’s transfer speed by enabling file caching 3. Using time in seconds* to indicate the duration for which cached content should endure, we may generalize the htaccess rules as such (edit file types and time value to suit your needs):

# cache images and flash content for one month

Header set Cache-Control "max-age=2592000"


# cache text, css, and javascript files for one week

Header set Cache-Control "max-age=604800"


# cache html and htm files for one day

Header set Cache-Control "max-age=43200"


# implement minimal caching during site development

Header set Cache-Control "max-age=5"


# explicitly disable caching for scripts and other dynamic files

Header unset Cache-Control


# alternate method for file caching
ExpiresActive On
ExpiresDefault A604800 # 1 week
ExpiresByType image/x-icon A2419200 # 1 month
ExpiresByType application/x-javascript A2419200 # 1 month
ExpiresByType text/css A2419200 # 1 month
ExpiresByType text/html A300 # 5 minutes
# disable caching for scripts and other dynamic files

ExpiresActive Off


* * Convert common time intervals into seconds:
* 300 = 5 minutes
* 2700 = 45 minutes
* 3600 = 1 hour
* 54000 = 15 hours
* 86400 = 1 day
* 518400 = 6 days
* 604800 = 1 week
* 1814400 = 3 weeks
* 2419200 = 1 month
* 26611200 = 11 months
* 29030400 = 1 year = never expires

Set the default language and character set

Here is an easy way to set the default language for pages served by your server (edit the language to suit your needs):

# set the default language
DefaultLanguage en-US

Likewise, here we are setting the default character set (edit to taste):

# set the default character set
AddDefaultCharset UTF-8

Declare specific/additional MIME types

# add various mime types
AddType application/x-shockwave-flash .swf
AddType video/x-flv .flv
AddType image/x-icon .ico

Send character set and other headers without meta tags

# send the language tag and default character set
# AddType 'text/html; charset=UTF-8' html
AddDefaultCharset UTF-8
DefaultLanguage en-US

Limit server request methods to GET and PUT

# limit server request methods to GET and PUT
Options -ExecCGI -Indexes -All
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK|OPTIONS|HEAD) RewriteRule .* - [F]

Selectively process files according to server request method

# process files according to server request method
Script PUT /cgi-bin/upload.cgi
Script GET /cgi-bin/download.cgi

Execute various file types through a cgi script

For those special occasions where certain file types need to be processed with some specific cgi script, let em know who sent ya:

# execute all png files via png-script.cgi
Action image/png /cgi-bin/png-script.cgi
Security

Prevent Acess to .htaccess

Add the following code block to your htaccess file to add an extra layer of security. Any attempts to access the htaccess file will result in a 403 error message. Of course, your first layer of defense to protect htaccess files involves setting htaccess file permissions via CHMOD to 644:

# secure htaccess file

order allow,deny
deny from all


Prevent Acess to a Specific File

To restrict access to a specific file, add the following code block and edit the file name, “secretfile.jpg”, with the name of the file that you wish to protect:

# prevent viewing of a specific file

order allow,deny
deny from all


Prevent acess to multiple file types

To restrict access to a variety of file types, add the following code block and edit the file types within parentheses to match the extensions of any files that you wish to protect:


Order Allow,Deny
Deny from all


Prevent Unauthorized Directory Browsing

Prevent unauthorized directory browsing by instructing the server to serve a “xxx Forbidden - Authorization Required” message for any request to view a directory. For example, if your site is missing it’s default index page, everything within the root of your site will be accessible to all visitors. To prevent this, include the following htaccess rule:

# disable directory browsing
Options All -Indexes

Conversely, to enable directory browsing, use the following directive:

# enable directory browsing
Options All +Indexes

Likewise, this rule will prevent the server from listing directory contents:

# prevent folder listing
IndexIgnore *

And, finally, the IndexIgnore directive may be used to prevent the display of select file types:

# prevent display of select file types
IndexIgnore *.wmv *.mp4 *.avi *.etc

Change Default Index Page

This rule tells the server to search for and serve “business.html” as the default directory index. This rule must exist in the htaccess files of the root directory for which you wish to replace the default index file (e.g., “index.html”):

# serve alternate default index page
DirectoryIndex business.html

This rule is similar, only in this case, the server will scan the root directory for the listed files and serve the first match it encounters. The list is read from left to right:

# serve first available alternate default index page from series
DirectoryIndex filename.html index.cgi index.pl default.htm

Disguise Script Extensions

To enhance security, disguise scripting languages by replacing actual script extensions with dummy extensions of your choosing. For example, to change the “.foo” extension to “.php”, add the following line to your htaccess file and rename all affected files accordingly:

# serve foo files as php files
AddType application/x-httpd-php .foo

# serve foo files as cgi files
AddType application/x-httpd-cgi .foo

Limit Access to the Local Area Network (LAN)

# limit access to local area network

order deny,allow
deny from all
allow from 192.168.0.0/33


Secure Directories by IP Address and/or Domain

In the following example, all IP addresses are allowed access except for 12.345.67.890 and domain.com:

# allow all except those indicated here

order allow,deny
allow from all
deny from 12.345.67.890
deny from .*domain\.com.*


In the following example, all IP addresses are denied access except for 12.345.67.890 and domain.com:

# deny all except those indicated here

order deny,allow
deny from all
allow from 12.345.67.890
allow from .*domain\.com.*


This is how to block unwanted visitors based on the referring domain. You can also save bandwidth by blocking specific file types — such as .jpg, .zip, .mp3, .mpg — from specific referring domains. Simply replace “scumbag” and “wormhole” with the offending domains of your choice:

# block visitors referred from indicated domains

RewriteEngine on
RewriteCond %{HTTP_REFERER} scumbag\.com [NC,OR]
RewriteCond %{HTTP_REFERER} wormhole\.com [NC,OR]
RewriteRule .* - [F]


Prevent or allow domain access for a specified range of IP addresses

There are several effective ways to block a range of IP addresses via htaccess. This first method blocks an IP range specified by thier CIDR (Classless Inter-Domain Routing) number. This method is useful for blocking mega-spammers such as RIPE, Optinet, and others. If, for example, you find yourself adding line after line of Apache deny directives for addresses beginning with the same first few numbers, choose one of them and try a whois lookup. Listed within the whois results will be the CIDR value representing every IP address associated with that particular network. Thus, blocking via CIDR is an effective way to eloquently prevent all IP instances of the offender from accessing your site. Here is a generalized example for blocking by CIDR (edit values to suit your needs):

# block IP range by CIDR number

order allow,deny
allow from all
deny from 10.1.0.0/16
deny from 80.0.0/8


Likewise, to allow an IP range by CIDR number:

# allow IP range by CIDR number

order deny,allow
deny from all
allow from 10.1.0.0/16
allow from 80.0.0/8


Another effective way to block an entire range of IP addresses involves truncating digits until the desired range is represented. As an IP address is read from left to right, its value represents an increasingly specific address. For example, a fictitious IP address of 99.88.77.66 would designate some uniquely specific IP address. Now, if we remove the last two digits (66) from the address, it would represent any address beginning with the remaining digits. That is, 99.88.77 represents 99.88.77.1, 99.88.77.2, … 99.88.77.99, …etc. Likewise, if we then remove another pair of digits from the address, its range suddenly widens to represent every IP address 99.88.x.y, where x and y represent any valid set of IP address values (i.e., you would block 256*256 = 65,536 unique IP addresses). Following this logic, it is possible to block an entire range of IP addresses to varying degrees of specificity. Here are few generalized lines exemplifying proper htaccess syntax (edit values to suit your needs):

# block IP range by address truncation

order allow,deny
allow from all
deny from 99.88.77.66
deny from 99.88.77.*
deny from 99.88.*.*
deny from 99.*.*.*


Likewise, to allow an IP range by address truncation:

# allow IP range by address truncation

order deny,allow
deny from all
allow from 99.88.77.66
allow from 99.88.77.*
allow from 99.88.*.*
allow from 99.*.*.*


Block or allow multiple IP addresses on one line

Save a little space by blocking multiple IP addresses or ranges on one line. Here are few examples (edit values to suit your needs):

# block two unique IP addresses
deny from 99.88.77.66 11.22.33.44
# block three ranges of IP addresses
deny from 99.88 99.88.77 11.22.33

Likewise, to allow multiple IP addresses or ranges on one line:

# allow two unique IP addresses
allow from 99.88.77.66 11.22.33.44
# allow three ranges of IP addresses
allow from 99.88 99.88.77 11.22.33

Miscellaneous rules for blocking and allowing IP addresses

Here are few miscellaneous rules for blocking various types of IP addresses. These rules may be adapted to allow the specified IP values by simply changing the deny directive to allow. Check ’em out (edit values to suit your needs):

# block a partial domain via network/netmask values
deny from 99.1.0.0/255.255.0.0

# block a single domain
deny from 99.88.77.66

# block domain.com but allow sub.domain.com
order deny,allow
deny from domain.com
allow from sub.domain.com

Stop Hotlinking, Serve Alternate Content

To serve ‘em some unexpected alternate content when hotlinking is detected, employ the following code, which will protect all files of the types included in the last line (add more types as needed). Remember to replace the dummy path names with real ones. Also, the name of the nasty image being served in this case is “eatme.jpe”, as indicated in the line containing the RewriteRule. Please advise that this method will also block services such as FeedBurner from accessing your images.

# stop hotlinking and serve alternate content

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?domain\.com/.*$ [NC]
RewriteRule .*\.(gif|jpg)$ http://www.domain.com/eatme.jpe [R,NC,L]


Note: To deliver a standard (or custom, if configured) error page instead of some nasty image of the Fonz, replace the line containing the RewriteRule in the above htaccess directive with the following line:

# serve a standard 403 forbidden error page
RewriteRule .*\.(gif|jpg)$ - [F,L]

Note: To grant linking permission to a site other than yours, insert this code block after the line containing the “domain.com” string. Remember to replace “goodsite.com” with the actual site domain:

# allow linking from the following site
RewriteCond %{HTTP_REFERER} !^http://(www\.)?goodsite\.com/.*$ [NC]

Block Evil Robots, Site Rippers, and Offline Browsers

Eliminate some of the unwanted scum from your userspace by injecting this handy block of code. After such, any listed agents will be denied access and receive an error message instead. Please advise that there are much more comprehensive lists available this example has been truncated for business purposes. Note: DO NOT include the “[OR]” on the very last RewriteCond or your server will crash, delivering “500 Errors” to all page requests.

# deny access to evil robots site rippers offline browsers and other nasty scum
RewriteBase /
RewriteCond %{HTTP_USER_AGENT} ^Anarchie [OR]
RewriteCond %{HTTP_USER_AGENT} ^ASPSeek [OR]
RewriteCond %{HTTP_USER_AGENT} ^attach [OR]
RewriteCond %{HTTP_USER_AGENT} ^autoemailspider [OR]
RewriteCond %{HTTP_USER_AGENT} ^Xaldon\ WebSpider [OR]
RewriteCond %{HTTP_USER_AGENT} ^Xenu [OR]
RewriteCond %{HTTP_USER_AGENT} ^Zeus.*Webster [OR]
RewriteCond %{HTTP_USER_AGENT} ^Zeus
RewriteRule ^.* - [F,L]

Or, instead of delivering a friendly error message (i.e., the last line), send these bad boys to the hellish website of your choice by replacing the RewriteRule in the last line with one of the following two examples:

# send em to a hellish website of your choice
RewriteRule ^.*$ http://www.hellish-website.com [R,L]

Or, to send em to a virtual blackhole of fake email addresses:

# send em to a virtual blackhole of fake email addresses
RewriteRule ^.*$ http://english-61925045732.spampoison.com [R,L]

You may also include specific referrers to your blacklist by using HTTP_REFERER. Here, we use the infamously scummy domain, “iaea.org” as our blocked example, and we use “yourdomain” as your domain (the domain to which you are blocking iaea.org):

RewriteCond %{HTTP_REFERER} ^http://www.iaea.org$
RewriteRule !^http://[^/.]\.yourdomain\.com.* - [F,L]

More Stupid Blocking Tricks

Note: Although these redirect techniques are aimed at blocking and redirecting nasty scumsites, the directives may also be employed for friendly redirection purposes:

# redirect any request for anything from spamsite to differentspamsite
RewriteCond %{HTTP_REFERER} ^http://.*spamsite.*$ [NC]
RewriteRule .* http://www.differentspamsite.com [R]

# redirect all requests from spamsite to an image of something at differentspamsite
RewriteCond %{HTTP_REFERER} ^http://.*spamsite.*$ [NC]
RewriteRule .* http://www.differentspamsite/something.jpg [R]

# redirect traffic from a certain address or range of addresses to another site
RewriteCond %{REMOTE_ADDR} 192.168.10.*
RewriteRule .* http://www.differentspamsite.com/index.html [R]

Even More Scum-Blocking Tricks

Here is a step-by-step series of code blocks that should equip you with enough knowledge to block any/all necessary entities. Read through the set of code blocks, observe the patterns, and then copy, combine and customize to suit your specific scum-blocking needs:

# set variables for user agents and referers and ip addresses
SetEnvIfNoCase User-Agent ".*(user-agent-you-want-to-block|php/perl).*" BlockedAgent
SetEnvIfNoCase Referer ".*(block-this-referrer|and-this-referrer|and-this-referrer).*" BlockedReferer
SetEnvIfNoCase REMOTE_ADDR ".*(666.666.66.0|22.22.22.222|999.999.99.999).*" BlockedAddress

# set variable for any class B network coming from a given netblock
SetEnvIfNoCase REMOTE_ADDR "66.154.*" BlockedAddress

# set variable for two class B networks 198.25.0.0 and 198.26.0.0
SetEnvIfNoCase REMOTE_ADDR "198.2(5|6)\..*" BlockedAddress

# deny any matches from above and send a 403 denied

order deny,allow
deny from env=BlockedAgent
deny from env=BlockedReferer
deny from env=BlockedAddress
allow from all


Password-Protect Directories

Here is an excellent online tool for generating the necessary elements for a password-protected directory:

# password protect directories
htaccess Password Generator

Password-protect Files, Directories, and More..

Secure site contents by requiring user authentication for specified files and/or directories. The first example shows how to password-protect any single file type that is present beneath the directory which houses the htaccess rule. The second rule employs the FilesMatch directive to protect any/all files which match any of the specified character strings. The third rule demonstrates how to protect an entire directory. The fourth set of rules provides password-protection for all IP’s except those specified. Remember to edit these rules according to your specific needs.

# password-protect single file

AuthType Basic
AuthName "Prompt"
AuthUserFile /home/path/.htpasswd
Require valid-user


# password-protect multiple files

AuthType basic
AuthName "Development"
AuthUserFile /home/path/.htpasswd
Require valid-user


# password-protect the directory in which this htaccess rule resides
AuthType basic
AuthName "This directory is protected"
AuthUserFile /home/path/.htpasswd
AuthGroupFile /dev/null
Require valid-user

# password-protect directory for every IP except the one specified
# place in htaccess file of a directory to protect that entire directory
AuthType Basic
AuthName "Personal"
AuthUserFile /home/path/.htpasswd
Require valid-user
Allow from 99.88.77.66
Satisfy Any

Require SSL (Secure Sockets Layer)

Here is an excellent method for requiring SSL (via askapache.com 3):

# require SSL
SSLOptions +StrictRequire
SSLRequireSSL
SSLRequire %{HTTP_HOST} eq "domain.tld"
ErrorDocument 403 https://domain.tld

# require SSL without mod_ssl
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]

Automatically CHMOD Various File Types

This method is great for ensuring the CHMOD settings for various file types. Employ the following rules in the root htaccess file to affect all specified file types, or place in a specific directory to affect only those files (edit file types according to your needs):

# ensure CHMOD settings for specified file types
# remember to never set CHMOD 777 unless you know what you are doing
# files requiring write access should use CHMOD 766 rather than 777
# keep specific file types private by setting their CHMOD to 400
chmod .htpasswd files 640
chmod .htaccess files 644
chmod php files 600

Disguise all file extensions

This method will disguise all file types (i.e., any file extension) and present them as .php files (or whichever extension you choose):

# diguise all file extensions as php
ForceType application/x-httpd-php

Protect against denial-of-service (DOS) attacks by limiting file upload size

One method to help protect your server against DOS attacks involves limiting the maximum allowable size for file uploads. Here, we are limiting file upload size to 10240000 bytes, which is equivalent to around 10 megabytes. For this rule, file sizes are expressed in bytes. Check here for help with various file size conversions. Note: this code is only useful if you actually allow users to upload files to your site.

# protect against DOS attacks by limiting file upload size
LimitRequestBody 10240000

Secure directories by disabling execution of scripts

Prevent malicious brainiacs from actively scripting secure directories by adding the following rules to the representative htaccess file (edit file types to suit your needs):

# secure directory by disabling script execution
AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi
Options -ExecCGI
Usability Tricks

Minimize CSS Image Flicker in IE6

Add the following htaccess rules to minimize or even eliminate CSS background-image “flickering” in MSIE6:

# minimize image flicker in IE6
ExpiresActive On
ExpiresByType image/gif A2592000
ExpiresByType image/jpg A2592000
ExpiresByType image/png A2592000

Deploy Custom Error Pages

Replicate the following patterns to serve your own set of custom error pages. Simply replace the “/errors/###.html” with the correct path and file name. Also change the “###” preceding the path to summon pages for other errors. Note: your custom error pages must be larger than 512 bytes in size or they will be completely ignored by Internet Explorer:

# serve custom error pages
ErrorDocument 400 /errors/400.html
ErrorDocument 401 /errors/401.html
ErrorDocument 403 /errors/403.html
ErrorDocument 404 /errors/404.html
ErrorDocument 500 /errors/500.html

Provide a Universal Error Document

# provide a universal error document
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /dir/error.php [L]

Employ Basic URL Spelling Check

This bit of voodoo will auto-correct simple spelling errors in the URL:

# automatically corect simple speling erors

CheckSpelling On


Instruct browser to download multimedia files rather than display them

Here is a useful method for delivering multimedia file downloads to your users. Typically, browsers will attempt to play or stream such files when direct links are clicked. With this method, provide a link to a multimedia file and a dialogue box will provide users the choice of saving the file or opening it. Here are a few htaccess rules demonstrating the technique (edit file types according to your specific needs):

# instruct browser to download multimedia files
AddType application/octet-stream .avi
AddType application/octet-stream .mpg
AddType application/octet-stream .wmv
AddType application/octet-stream .mp3

Instruct server to display source code for dynamic file types

There are many situations where site owners may wish to display the contents of a dynamic file rather than executing it as a script. To exercise this useful technique, create a directory in which to place dynamic files that should be displayed rather than executed, and add the following line of code to the htaccess file belonging to that directory. This method is known to work for .pl, .py, and .cgi file-types. Here it is:

RemoveHandler cgi-script .pl .py .cgi

Redirect visitors to a temporary site during site development

During web development, maintenance, or repair, send your visitors to an alternate site while retaining full access for yourself. This is a very useful technique for preventing visitor confusion or dismay during those awkward, web-development moments. Here are the generalized htaccess rules to do it (edit values to suit your needs):

# redirect all visitors to alternate site but retain full access for you
ErrorDocument 403 http://www.alternate-site.com
Order deny,allow
Deny from all
Allow from 99.88.77.66

Provide a password prompt for visitors during site development

Here is another possible solution for "hiding" your site during those private, site-under-construction moments. Here we are instructing Apache to provide visitors with a password prompt while providing open access to any specifically indicated IP addresses or URL’s. Edit the following code according to your IP address and other development requirements (thanks to Caleb at askapache.com for sharing this trick 3):

# password prompt for visitors
AuthType basic
AuthName "This site is currently under construction"
AuthUserFile /home/path/.htpasswd
AuthGroupFile /dev/null
Require valid-user
# allow webmaster and any others open access
Order Deny,Allow
Deny from all
Allow from 111.222.33.4
Allow from favorite.validation/services/
Allow from googlebot.com
Satisfy Any

Prevent file or directory access according to specified time periods

Prevent viewing of all pictures of Fonzi during the midnight hour — or any files during any time period — by using this handy htaccess ruleset:

# prevent access during the midnight hour
RewriteCond %{TIME_HOUR} ^12$
RewriteRule ^.*$ - [F,L]

# prevent access throughout the afternoon
RewriteCond %{TIME_HOUR} ^(12|13|14|15)$
RewriteRule ^.*$ - [F,L]
Redirect Tricks

Important Note About Redirecting via mod_rewrite

For all redirects using the mod_rewrite directive, it is necessary to have the RewriteEngine enabled. It is common practice to enable the mod_rewrite directive in either the server configuration file or at the top of the site’s root htaccess file. If the mod_rewrite directive is not included in either of these two places, it should be included as the first line in any code block that utilizes a rewrite function (i.e., mod_rewrite), but only needs to be included once for each htaccess file. The proper mod_rewrite directive is included here for your convenience, but may or may not also be included within some of the code blocks provided in this article:

# initialize and enable rewrite engine
RewriteEngine on

Redirect from http://www.domain.com to http://domain.com

This method uses a “301 redirect” to establish a permanent redirect from the “www-version” of a domain to its respectively corresponding “non-www version”. Be sure to test immediately after preparing 301 redirects and remove it immediately if any errors occur. Use a “server header checker” to confirm a positive 301 response. Further, always include a trailing slash “/” when linking directories. Finally, be consistent with the “www” in all links (either use it always or never).

# permanently redirect from www domain to non-www domain
RewriteEngine on
Options +FollowSymLinks
RewriteCond %{HTTP_HOST} ^www\.domain\.tld$ [NC]
RewriteRule ^(.*)$ http://domain.tld/$1 [R=301,L]

Redirect from http://old-domain.com to http://new-domain.com

For a basic domain change from “old-domain.com” to “new-domain.com” (and folder/file names have not been changed), use the Rewrite rule to remap the old domain to the new domain. When checking the redirect live, the old domain may appear in the browser’s address bar. Simply check an image path (right-click an image and select “properties”) to verify proper redirection. Remember to check your site thoroughly after implementing this redirect.

# redirect from old domain to new domain
RewriteEngine On
RewriteRule ^(.*)$ http://www.new-domain.com/$1 [R=301,L]

Redirect String Variations to a Specific Address

For example, if we wanted to redirect any requests containing the character string, “perish”, to our main page at http://perishablepress.com/, we would replace “some-string” with “perish” in the following code block:

# redirect any variations of a specific character string to a specific address
RewriteRule ^some-string http://www.domain.com/index.php/blog/target [R]

Here are two other methods for accomplishing string-related mapping tasks:

# map URL variations to the same directory on the same server
AliasMatch ^/director(y|ies) /www/docs/target

# map URL variations to the same directory on a different server
RedirectMatch ^/[dD]irector(y|ies) http://domain.com

Other Fantastic Redirect Tricks

Redirect an entire site via 301:

# redirect an entire site via 301
redirect 301 / http://www.domain.com/

Redirect a specific file via 301:

# redirect a specific file via 301
redirect 301 /current/currentfile.html http://www.newdomain.com/new/newfile.html

Redirect an entire site via permanent redirect:

# redirect an entire site via permanent redirect
Redirect permanent / http://www.domain.com/

Redirect a page or directory via permanent redirect:

# redirect a page or directory
Redirect permanent old_file.html http://www.new-domain.com/new_file.html
Redirect permanent /old_directory/ http://www.new-domain.com/new_directory/

Redirect a file using RedirectMatch:

# redirect a file using RedirectMatch
RedirectMatch 301 ^.*$ http://www.domain.com/index.html

Note: When redirecting specific files, use Apache‘s Redirect rule for files within the same domain. Use Apache‘s RewriteRule for any domains, especially if they are different. The RewriteRule is more powerful than the Redirect rule, and thus should serve you more effectively.

Thus, use the following for a stronger, harder page redirection (first line redirects a file, second line a directory, and third a domain):

# redirect files directories and domains via RewriteRule
RewriteRule http://old-domain.com/old-file.html http://new-domain.com/new-file.html
RewriteRule http://old-domain.com/old-dir/ http://new-domain.com/new-dir/
RewriteRule http://old-domain.com/ http://new-domain.com/

Send visitors to a subdomain

This rule will ensure that all visitors are viewing pages via the subdomain of your choice. Edit the "subdomain", "domain", and "tld" to match your subdomain, domain, and top-level domain respectively:

# send visitors to a subdomain
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^subdomain\.domain\.com$ [NC]
RewriteRule ^/(.*)$ http://subdomain.domain.tld/$1 [L,R=301]

More fun with RewriteCond and RewriteRule

# rewrite only if the file is not found
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)special\.html?$ cgi-bin/special/special-html/$1

# rewrite only if an image is not found
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule images/special/(.*).gif cgi-bin/special/mkgif?$1

# seo-friendly rewrite rules for various directories
RewriteRule ^(.*)/aud/(.*)$ $1/audio-files/$2 [L,R=301]
RewriteRule ^(.*)/img/(.*)$ $1/image-files/$2 [L,R=301]
RewriteRule ^(.*)/fla/(.*)$ $1/flash-files/$2 [L,R=301]
RewriteRule ^(.*)/vid/(.*)$ $1/video-files/$2 [L,R=301]

# broswer sniffing via htaccess environmental variables
RewriteCond %{HTTP_USER_AGENT} ^Mozilla.*
RewriteRule ^/$ /index-for-mozilla.html [L]
RewriteCond %{HTTP_USER_AGENT} ^Lynx.*
RewriteRule ^/$ /index-for-lynx.html [L]
RewriteRule ^/$ /index-for-all-others.html [L]

# redirect query to Google search
Options +FollowSymlinks
RewriteEngine On
RewriteCond %{REQUEST_URI} .google\.php*
RewriteRule ^(.*)$ ^http://www.google.com/search?q=$1 [R,NC,L]

# deny request according to the request method
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK|OPTIONS|HEAD)$ [NC]
RewriteRule ^.*$ - [F]

# redirect uploads to a better place
RewriteCond %{REQUEST_METHOD} ^(PUT|POST)$ [NC]
RewriteRule ^(.*)$ /cgi-bin/upload-processor.cgi?p=$1 [L,QSA]

More fun with Redirect 301 and RedirectMatch 301

# seo friendly redirect for a single file
Redirect 301 /old-dir/old-file.html http://domain.com/new-dir/new-file.html

# seo friendly redirect for multiple files
# redirects all files in dir directory with first letters xyz
RedirectMatch 301 /dir/xyz(.*) http://domain.com/$1

# seo friendly redirect entire site to a different domain
Redirect 301 / http://different-domain.com
WordPress Tricks

Secure WordPress Contact Forms

Protect your insecure WordPress contact forms against online unrighteousness by verifying the domain from whence the form is called. Remember to replace the “domain.com” and “contact.php” with your domain and contact-form file names, respectively.

# secure wordpress contact forms via referrer check
RewriteCond %{HTTP_REFERER} !^http://www.domain.com/.*$ [NC]
RewriteCond %{REQUEST_POST} .*contact.php$
RewriteRule .* - [F]

WordPress Permalinks

In our article, The htaccess rules for all WordPress Permalinks, we revealed the precise htaccess directives used by the WordPress blogging platform for permalink functionality. Here, for the sake of completeness, we repeat the directives only. For more details please refer to the original article:

If WordPress is installed in the site’s root directory, WordPress creates and uses the following htaccess directives:

# BEGIN WordPress

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

If WordPress is installed in some subdirectory “foo”, WordPress creates and uses the following htaccess directives:

# BEGIN WordPress

RewriteEngine On
RewriteBase /foo/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /foo/index.php [L]

# END WordPress
Random Tricks

Activate SSI for HTML/SHTML file types:

# activate SSI for HTML and or SHTML file types
AddType text/html .html
AddType text/html .shtml
AddHandler server-parsed .html
AddHandler server-parsed .shtml
AddHandler server-parsed .htm

Grant CGI access in a specific directory:

# grant CGI access in a specific directory
Options +ExecCGI
AddHandler cgi-script cgi pl
# to enable all scripts in a directory use the following
SetHandler cgi-script

Disable magic_quotes_gpc for PHP enabled servers:

# turn off magic_quotes_gpc for PHP enabled servers

php_flag magic_quotes_gpc off


Enable MD5 digests:

Note: enabling this option may result in a relative decrease in server performance.

# enable MD5 digests via ContentDigest
ContentDigest On

Expression Engine Tricks:

# send Atom and RSS requests to the site docroot to be rewritten for ExpressionEngine
RewriteRule .*atom.xml$ http://www.yoursite.com/index.php/weblog/rss_atom/ [R]
RewriteRule .*rss.xml$ http://www.yoursite.com/index.php/weblog/rss_2.0/ [R]

# cause all requests for index.html to be rewritten for ExpressionEngine
RewriteRule /.*index.html$ http://www.domain.com/index.php [R]