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 site’s root directory.

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. For more information, check out my tutorial commenting your .htaccess code.

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.

.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.

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” response 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 a 410 “Gone” response (indicating that the resource no longer exists.

[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 client to request the new content.

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 _

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

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 next section for more information):

For directives that require AllowOverride in order to function, such as FollowSymLinks (see previous section), 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 privileges only in the specified directory:

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:

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 inherit the httpd.conf rules by including this directive:

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:

Caleb over at askapache.com explains how to dramatically improve your site’s transfer speed by enabling file caching. Using time in seconds (see conversion chart) 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):

Prevent unauthorized directory browsing by instructing the server to serve a 403 “Forbidden” response for any request to view a directory. For example, if your site is missing its 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:

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:

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:

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

# allow all except those indicated here
<Limit GET POST PUT>
Order allow,deny
Allow from all
Deny from 12.345.67.890
Deny from example\.com
</Limit>

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

# deny all except those indicated here
<Limit GET POST PUT>
Order deny,allow
Deny from all
Allow from 12.345.67.890
Allow from example\.com
</Limit>

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:

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 their 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
<Limit GET POST PUT>
Order allow,deny
Allow from all
Deny from 10.1.0.0/16
Deny from 80.0.0/8
</Limit>

Likewise, to allow an IP range by CIDR number:

# allow IP range by CIDR number
<Limit GET POST PUT>
Order deny,allow
Deny from all
Allow from 10.1.0.0/16
Allow from 80.0.0/8
</Limit>

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
<Limit GET POST PUT>
Order allow,deny
Allow from all
Deny from 99.88.77.66
Deny from 99.88.77.*
Deny from 99.88.*.*
Deny from 99.*.*.*
</Limit>

Likewise, to allow an IP range by address truncation:

# allow IP range by address truncation
<Limit GET POST PUT>
Order deny,allow
Deny from all
Allow from 99.88.77.66
Allow from 99.88.77.*
Allow from 99.88.*.*
Allow from 99.*.*.*
</Limit>

Note: for these examples, we are using <Limit> to restrict the rule set to the specified request methods (GET, POST, and PUT). So you can either customize which methods should be targeted, or to target all requests, simply remove the surrounding <Limit> container.

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):

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.

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:

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 be advised that there are much more comprehensive blacklists available this example has been truncated for performance purposes. Note: DO NOT include the [OR] on the very last RewriteCond or your server will throw an error.

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:

You may also add 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):

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:

The fourth example provides password-protection for all IPs except that which is specified, 99.88.77.66.

# 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

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):

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.

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 or they will be completely ignored by Internet Explorer:

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):

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:

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

For more in-depth information and advanced techniques, check out the following tutorials:

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 URLs. Edit the following code according to your IP address and other development requirements (thanks to Caleb at askapache.com for sharing this trick):

For more information on numerical regular expressions, check out Redirecting URLs that Include Numbers. The article is about redirecting requests, but contains a lot of useful regex infos for matching numbers.

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:

# enable rewrite engine
RewriteEngine on

Note that it’s fine to include this directive multiple times in the same .htaccess file.

This technique is referred to as www canonicalization. It uses a “301 redirect” to establish a permanent redirect from the “www” version of a domain to its 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 proper 301 response. Further, always include a trailing slash / when linking directories. Finally, be consistent with the www subdomain in all links (either use it always or never).

For a basic domain change from old-domain.com to new-domain.com (with identical files and resources on both domains), use the Rewrite rule to remap the old domain to the new domain. 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]

Once in place, this rule set redirects all requests from old-domain.com to new-domain.com.

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

Here we are using RedirectMatch to match any request for /xyz/ or any file or directory contained in /xyz/. If the request matches, it will be redirected via 301 “Permanent” status code to the new domain. The $1 in this example represents whatever is matched by (.*). So if the requested URI is /dir/xyz/bananaz.php, it will be redirected to http://domain.com/bananaz.php.

To redirect an entire, such that every URL is redirected to the same URL on the new domain, use Redirect:

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.

In my article, The .htaccess rules for all WordPress Permalinks, I reveal 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. There are two possibilities for this technique: WordPress installed in the site root directory, or WordPress installed in its own directory (subdirectory).

WordPress installed in site root

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

Great Information!
Thanks for taking time to put this informative post together.
———-
but I do have a stumper for you. My BIG problem are these Hotlinking thieves. Do you know that my host just sent me a $2000 bandwidth bill for April? And I cant afford that. So we dug a little and found that my images & mpg clips were being Hotlinked. Not just a little, it was ALOT! and I’ve tried to do everything I can, I even bought AHL from antihotlinking.com to protect my mpg clips, but these Leechers are STILL getting through. So I’m sitting here the other day frustrated out of my mind – and something came to me, but before I tell you what came to me, I’ve pasted my present .htaccess code below (I only changed the domains):
——————————-

I’ve obviously got major problems in the code above. And I have no clue where or what to even do about it.

Oh – sorry, let me get back to that BIG idea that came to me. Ya see – in my page source code, I can either use a “reletive” or the “full” path to my images & mpgs. But these Hotlinkers have to use the “full” path if they want to hotlink anything. So is there a way to configure the .htaccess code to ONLY allow from “reletive” paths which obviously would be from me? Then – block or redirect any hotlinker using pages with “Full” paths to my files? I dont know. Cause to me, even if theres no referrer info or whatever, that hotlinker MUST use the full path to my files. I mean the server must be able to differentiate between someone (hotlinker) trying to get in to my server externally as opposed to someone internally – for example – like one of my legitimate customers whose landed on one of my advertisment pages already.. Wow I really hope this all makes sense. Please let me know what you think.
Thanks again,
Dman

Projects

About the site

Perishable Press is the work of Jeff Starr, professional developer, designer, author, and publisher with over 10 years of experience.
Check out some of Jeff's books and projects, follow on Twitter, or learn more »

Fun fact: Perishable Press has been online since 2005, and features over 800 articles and more than 11,000 comments. More stats »