Htaccess Techniques
Contents
- 1 Overview
- 2 Adding headers
- 3 Denying access
- 4 Error documents
- 5 Faster page loading
- 6 File extensions
- 7 Index options
- 8 Redirects and rewrites
- 9 Prevent image hotlinking
- 10 Security
- 11 Secure Hosting
- 12 Using SSI on files with an .html extension
- 13 Miscellaneous
- 14 See also
Overview
This page lists several examples of what you can add to your .htaccess file.
Adding headers
Adding a content-type=UTF-8 header
Use either one of the following in an .htaccess file to force the specific content-type header. This adds the header without having to use a meta tag:
AddDefaultCharset UTF-8 AddDefaultCharset ISO-8859-1
Adding a language header
Use the following in an .htaccess file to specify a language header. This adds the header without having to use a meta tag:
DefaultLanguage en-us
Denying access
Deny access to files
Denying access to specific file extensions
The following code forces any file ending in .inc to throw a 403 Forbidden error when visited:
<Files ~ "\.inc$"> Order Allow,Deny Deny from All </Files>
File names beginning with a dot are considered "hidden" by UNIX. Usually, you don't want to serve them to visitors.
DreamHost already disallows retrieving '.htaccess' and '.htpasswd', but you can recursively deny all access to all hidden files by placing the following into a top-level .htaccess:
RedirectMatch 403 /\..*$
Deny access to folders
Denying access to a directory listing
If you don't have an index file in your directory, all of your files are listed in a directory list for anyone to view. The following code forces this directory listing to throw a 403 Forbidden error instead when visited:
Options -Indexes
Denying access during a specific hour of the day
If you wish to block access to files in a directory during a specific time of day, then you can do so by adding the following code to an .htaccess file:
RewriteEngine On # If the hour is 16 (4 PM) RewriteCond %{TIME_HOUR} ^16$ # Then deny all access RewriteRule ^.*$ - [F,L]
If someone visits the directory anytime between 4:00 – 4:59 pm, a 500 Internal Server error is thrown. You can also specify multiple hours as well:
RewriteEngine On # Multiple hour blocks # If the hour is 4 PM or 5 PM or 8 AM RewriteCond %{TIME_HOUR} ^16|17|08$ # Then deny all access RewriteRule ^.*$ - [F,L]
Denying access to a directory
If you have a directory named 'blah' that you want to block, but it can occur anywhere in your directory tree, use the following:
RewriteEngine On RewriteRule (^|/)blah(/|$) - [F]
Denying access from specific IP addresses
If you have problems with certain visitors to your website, you can easily ban them. There are two different ways to ban visitors:
- using their IP address, or
- the domain name from which they are visiting.
Here's an example that denies a user by their IP address:
deny from 173.236.241.100
When the user tries to connect to your site from that specific IP, they see a 403 Forbidden page instead. If you want to block an entire block of IPs, just leave the last octet off. For example:
deny from 173.236.241.
This denies access from anyone using an IP in the range from 173.236.241.0 all the way up to 173.236.241.255.
The following link is a useful online tool that automatically generates an IP range for you:
Allowing access from a specific IP
If you need to deny access to your site to everyone while still allowing yourself or another specific IP address to visit it, you can use something like this:
order deny,allow deny from all allow from <YOUR_IP_ADDRESS>
Denying access from a specific domain
This denies access from anyone connecting to your site from www.example.com. If someone clicks on a link at example.com that redirects to your site, they then see a 403 Forbidden error:
SetEnvIfNoCase Referer "example.com" bad_referer Order Allow,Deny Allow from ALL Deny from env=bad_referer
This example throws a 500 Internal Server Error for anyone linking from example.com:
RewriteEngine on RewriteCond %{HTTP_REFERER} example\.com [NC,OR] RewriteRule .* - [F]
The following example redirects any visitor connecting from example.com to google.com:
RewriteEngine On RewriteCond %{HTTP_REFERER} ^http://example.com/ RewriteRule /* http://www.google.com [R,L]
Error documents
For details on how to create and manage error pages, please view the following article:
Faster page loading
GZIP
DEFLATE is a lossless data compression algorithm similar to gzip, but it works in Apache 2. In the past, mod_gzip was a recommended tool. But DreamHost uses Apache 2 and mod_deflate, which calls gzip on the back end automatically. If you want to, you can add additional encoding types to the filter for things like XML or JSON. For example:
#Gzip <ifmodule mod_deflate.c> AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript text/javascript </ifmodule> #End Gzip
View the following page for further details:
Browser caching
Using mod_expires, you can tell visiting browsers to hold on to certain files longer (likes images, which are rarely changed). This example shows how to cache specific file types for specific periods of time:
# BEGIN Expire headers <ifModule mod_expires.c> ExpiresActive On ExpiresDefault "access plus 5 seconds" ExpiresByType image/x-icon "access plus 2592000 seconds" ExpiresByType image/jpeg "access plus 2592000 seconds" ExpiresByType image/png "access plus 2592000 seconds" ExpiresByType image/gif "access plus 2592000 seconds" ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds" ExpiresByType text/css "access plus 604800 seconds" ExpiresByType text/javascript "access plus 216000 seconds" ExpiresByType application/javascript "access plus 216000 seconds" ExpiresByType application/x-javascript "access plus 216000 seconds" ExpiresByType text/html "access plus 600 seconds" ExpiresByType application/xhtml+xml "access plus 600 seconds" </ifModule> # END Expire headers
Alternately, you can use mod_headers:
# BEGIN Caching <ifModule mod_headers.c> <filesMatch "\\.(ico|pdf|flv|jpg|jpeg|png|gif|swf)$"> Header set Cache-Control "max-age=2592000, public" </filesMatch> <filesMatch "\\.(css)$"> Header set Cache-Control "max-age=604800, public" </filesMatch> <filesMatch "\\.(js)$"> Header set Cache-Control "max-age=216000, private" </filesMatch> <filesMatch "\\.(xml|txt)$"> Header set Cache-Control "max-age=216000, public, must-revalidate" </filesMatch> <filesMatch "\\.(html|htm|php)$"> Header set Cache-Control "max-age=1, private, must-revalidate" </filesMatch> </ifModule> # END Caching
PageSpeed
If you have Pagespeed enabled for your domain, you can take advantage of additional settings such as Remove Comments:
<IfModule pagespeed_module> ModPagespeed on ModPagespeedEnableFilters remove_comments </IfModule>
Generally safe options to add are:
- remove_comments – removes HTML comments (low risk)
- rewrite_javascript – minifies JS (med. to high risk, depending on your site)
- rewrite_css – parses linked and inline CSS, rewrites the images found, and minifies the CSS (med. risk)
- rewrite_images – compresses and optimizes images (med. risk)
- elide_attributes – removes attributes from tags (med. risk)
- move_css_to_head – combines CSS and moves it to the head of your file (low risk)
If you add multiple options, they can be on one line separated by commas. But do not use spaces. For example:
ModPagespeedEnableFilters remove_comments,move_css_to_head
File extensions
Changing the file extension
This example allows you to use a .zig extension in addition to the regular .php extension. So, you could access a file at example.zig as well as example.php:
Options +FollowSymlinks RewriteEngine On RewriteBase / RewriteRule ^(.+)\.zig$ /$1.php [NC,L]
Forcing other file extensions to load as PHP
View the following article which gives several examples on how to force any file extension to load as a .php file.
Removing the file extension
This example completely removes the file extension from your URL. So, example.php would appear as example. The following example is for .php files, but for any other type, just replace .php with your desired type and add those lines and extensions in the same way:
RewriteEngine On RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*index\ HTTP/ RewriteRule ^(.*)index$ http://example.com/$1 [L,R=301] RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^([^/]+)/$ http://example.com/$1 [L,R=301] RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.+)\.php\ HTTP/ RewriteRule ^(.+)\.php$ http://example.com/$1 [L,R=301] RewriteRule ^([a-z]+)$ /$1.php [L]
Allowing a file to load without the extension
This example does not automatically remove the file extension. However, it does allow the file to be loaded without the extension. So, if example.com/test.php exists, you can then load it as example.com/test:
Options +FollowSymlinks RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}.php -f RewriteRule ^(.+)$ /$1.php [L,QSA]
Index options
What are directory indexes?
If the Indexes option is enabled (which it is by default), visitors can look inside any directory that does not have an index.html (or index.php, etc.) file in it and browse the contents of the directory. This is probably not the behavior you typically want, especially if said directory contains something like script configuration files that could pose a security risk.
One way around this problem is to put an empty index.html in every single folder of your site, but for sites with a large hierarchy of directory structure, this can quickly become very tedious. Fortunately, there's a better way:
Turning off directory indexes
Place the following in an .htaccess file in your main domain name folder to disable directory indexes throughout your entire site:
Options -Indexes
Now, if someone tries to browse the contents of any directory of your site, they'll get a 403 (Forbidden) error.
Turning on directory indexes for specific folders
If there's a particular directory in your site that you do want people to be able to browse, simply create a new .htaccess file in that particular folder. Add the following:
Options +Indexes
This now overrides the "global" setting and allow users to view the content of that directory.
Alternative index files
When a visitor accesses your website, the server checks the folder for an index file. Some examples of common index files are:
- index.htm
- index.html
- index.php
- index.cgi
- index.pl
The supported index files depend on the how the server is set up. DreamHost's servers are set to:
DirectoryIndex index.html index.shtml index.htm Index.html Index.htm Index.shtml default.htm Default.htm default.html Default.html default.shtml Default.shtml page1.html index.pl index.cgi index.php index.php3 index.phtml home.htm home.html home.shtml index.wml index.pcgi quickstart.html
- As long as you name your "index" file any one of the above, it will automatically load.
- When you add a new domain/subdomain to your account, DreamHost creates a quickstart.html file for you and places it in your directory which loads by default unless you delete it or add your own index file.
- If you have two files with names from the list above, Apache shows the one that appears first (e.g., index.html will show up, even if you have an index.php file in the same directory).
- You can change your own DirectoryIndex setting to be anything you like using an .htaccess file. If the server cannot find an index file, it tries to display an index of all the files within the current directory; however if this is disabled, the server ends up displaying a 404 forbidden error.
- Using .htaccess, you can use a completely different index file instead of the defaults listed above. To do this, insert the following line into an .htaccess file:
DirectoryIndex pagename.html
Change pagename.html to the page that you wish to use as the index file. If you specify something like example.html to be the directoryindex and you have not uploaded this file to your web directory, Apache shows a listing of all files since it cannot find the one you specified. Be careful where you place this rule (or any rule), because it is recursive.
Fail safe directory listing
The following allows a specific file to load just in case there is no default index file already set up:
Options -Indexes DirectoryIndex index.php index.html /example.php
When a visitor requests a directory, Apache searches for index.php, then index.html, and if neither are found it displays /example.php.
Redirects and rewrites
Redirecting a URL
Using Redirect in an .htaccess file enables you to redirect users from an old page to a new page without having to keep the old page. For example, if you use index.html as your index file and then later rename index.html to home.html, you could set up a redirect to send users from index.html to home.html. For example:
Redirect /path/to/old/file/old.html http://www.example.com/new/file/new.html
The first path to the old file must be a local UNIX path, NOT the full path. So, if the .htaccess file is in the directory /example.com, you would not include /home/exampleuser/example.com in the local UNIX path. The first / represents the example.com directory. If the old file was in that directory, you would follow the / with the old file name.
The second path to the new file can be a local UNIX path, but can also be a full URL to link to a page on a different server or the same server. Here are a few examples of some redirects:
Redirect /index.html /new/ Redirect /index.html /default.html Redirect /private/ http://www.example.com/private/ Redirect /img/logo.gif http://www.example.com/images/logo.gif
Another form of redirection uses the RedirectMatch command:
RedirectMatch "^/oldfile\.html/?$" "http://example.com/newfile.php"
You can also redirect 404 errors. Instead of throwing a 404 page, this redirects to the homepage of the website.
ErrorDocument 404 http://example.com/
Redirect non-existing pages to index.php
If a visitor attempts to access a page that doesn't exist, they are presented with a 404 error. You can instead redirect any request to a non-existing page to your index.php file (or any index file) by adding the following code in your .htaccess:
Options +SymLinksIfOwnerMatch RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L]
If your index page isn't index.php, just change the last line to your actual index file. Then the visitor is redirected back to your home page.
Automatically loading a subdirectory
This example redirects the ROOT domain's URL to any subdirectory. In this example, it automatically loads example.com/subdir1:
RewriteEngine on RewriteRule ^$ /subdir1/ [L]
Forcing www in the URL
RewriteEngine On RewriteCond %{HTTP_HOST} ^example.com RewriteRule (.*) http://www.example.com/$1 [R=301,L]
Removing www in the URL
RewriteEngine On RewriteCond %{HTTP_HOST} ^www.example.com RewriteRule (.*) http://example.com/$1 [R=301,L]
Redirecting a file to Google Translate
The following redirects any file ending with -fr, -de, -es, and so on to translate.google.com for that language. For example, create a file named example.html-fr. Then, create a file named example.html with the content you wish to display. When the visitor loads example.html-fr, it redirects to Google which translates the content of example.html. The following code redirects that file to Google to translate:
Options +FollowSymlinks RewriteEngine On RewriteBase / RewriteRule ^(.*)-(fr|de|es|it|pt)$ http://www.google.com/translate_c?hl=$2&sl=en&u=http://example.com/$1 [R,NC]
Rewriting a URL
This example rewrites a URL to another URL. This rewrites example.com/1.html to example.com/abc.php?id=1
Options +FollowSymLinks RewriteEngine On RewriteRule ^([0-9]+).html /abc.php?id=$1 [QSA,L]
The following explains the rules above:
- ([0-9]+)
- allows any digit, and only any digit, 1 or more times.
- ([a-z-]*)
- allows any lowercase letter, plus “-” for word separation, 0 or more times. If you want it to support uppercase too, use “([a-zA-Z-]*) RewriteRule ^place/([a-zA-Z-]*).html /place/abc.php?id=$1 [QSA,L]
- [QSA,L]
- appends this to your internal scripting query string, and makes it the Last rewrite rule executed.
After using this method, you can retrieve the webpage with either address type. This is handy for retro-fitting a website that was not designed with mod_rewrite in mind. This is good because it does not destroy any bookmarks saved on users computers.
View the following link for more information and examples about mod-rewrite:
Rewriting non-existing links to index.php
The following redirects all links to files or folders that do not exist to index.php. However, if the file or directory does exist, it loads normally:
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule>
Prevent image hotlinking
Hot linking or bandwidth stealing is a common problem. It happens when people link to files and images on a different server and display them on their own website; this uses the bandwidth of the original owner at their expense. By entering the lines below, you can prevent hotlinking to your website:
RewriteEngine On RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{HTTP_REFERER} !^http://(www\.)?example.com/.*$ [NC] RewriteRule \.(gif|jpg)$ http://www.example.com/hotlink.gif [R,L]
In the example above, change 'example.com' to your website URL. This causes any hotlinked image to fail to load. You can change the last line to point to any image you like. This image should explain that hot linking is disabled on your server.
Here is another example:
RewriteEngine on RewriteCond %{HTTP_REFERER} !^http://example.com.*$ [NC] RewriteCond %{HTTP_REFERER} !^http://www.example.com.*$ [NC] RewriteRule .*\.(gif|jpg|jpeg|bmp)$ http://www.example.com/stophotlinking.jpg [R,NC]
You can change the last line to point to any image you like. This image should explain that hot linking is disabled on your server.
If you don't wish to take the manual approach, you can prevent hotlinking by enabling it in the panel. To enable, navigate to the (Panel > 'Goodies' > 'Htaccess/WebDAV') page. Click on your domain and proceed with the steps to enable this feature.
Blocking specific domains
The following code fails to load a hotlinked file, but no error is thrown. So, if the site example.com contains a hotlinked image to your site, it would fail to load on their site:
RewriteEngine On RewriteCond %{HTTP_REFERER} ^http://(www\.)?example\.com(/.*)*$ [NC,OR] RewriteRule \.(jpeg|JPEG|jpe|JPE|jpg|JPG|gif|GIF|png|PNG|mng|MNG)$ - [F]
To protect other resources, such as video and audio files, add additional extensions to the RewriteRule parentheses block.
Allowing only specific domains
The following code only allows specific sites to load content. For example, the site example.com has all of the content. The following code allows only example.com and websitehelp.support to load the content. All other sites attempting to request any resource fail to load the resource, but no errors are thrown:
RewriteEngine On RewriteCond %{HTTP_REFERER} !^http://(www\.)?websitehelp\.support(/.*)*$ [NC] RewriteCond %{HTTP_REFERER} !^http://(www\.)?example\.com(/.*)*$ [NC] RewriteCond %{HTTP_REFERER} !^$ RewriteRule \.(jpeg|gif|png)$ - [F]
In addition, since a user agent may not always specify an HTTP_REFERER value, the RewriteCond %{HTTP_REFERER} !^$ line allows the request to go through if the HTTP_REFERER value consists of a blank string.
For further examples on how to block traffic by IP or domain, please view the Denying access section above.
Security
Authentication
You can use an .htaccess file to password protect a file or folder using basic authentication.
- Create an .htpasswd file in the directory you wish to password protect.
- Create this file using the htpasswd utility. For the first user, say user1, run the following:
htpasswd -c /home/username/example.com/.htpasswd user1
- Enter the password for the user. This creates a password for a user named 'user1'.
- Run it again (without the -c option) for any other users you wish to allow access to your directory.
- Set the permissions on this file to 644.
View the following page for further information:
Next, create an .htaccess file.
This example password protects an entire directory:
#Protect Directory AuthName "Dialog prompt" AuthType Basic AuthUserFile /home/user1/.htpasswd Require valid-user
This example password protects a single file:
#Protect single file <Files admin.php> AuthName "Dialog prompt" AuthType Basic AuthUserFile /home/user1/.htpasswd Require valid-user </Files>
This example protects multiple files:
#Protect multiple files <FilesMatch "^(admin|staff).php$"> AuthName "Dialog prompt" AuthType Basic AuthUserFile /home/user1/.htpasswd Require valid-user </FilesMatch>
There is also a simpler way to do this in the DreamHost panel. Navigate to the (Panel > 'Goodies' > 'Htaccess/WebDAV') page. You can then set up password protection there.
Secure Hosting
Forcing the domain to serve securely using HTTPS
The following forces any http request to be rewritten using https. For example, the following code forces a request to http://example.com to load https://example.com:
RewriteEngine On RewriteCond %{HTTPS} !=on RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
The following alternative also forces directly linked resources (images, css, etc.) to use https:
RewriteEngine On RewriteCond %{HTTPS} !=on RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
If this isn't working for you, first check your line endings. Copy/paste from your web browser into a text editor may not work right, so after pasting into your text editor you should delete each line break and add it back in (line break = return key).
An extra secure method to force a domain to only use SSL (HTTPS)
This method fixes a double login problem. If you wish to ensure that your server is only serving documents over an encrypted SSL channel (you wouldn't want visitors to submit an .htaccess password prompt on an unencrypted connection), then you must use the SSLRequireSSL directive with the +StrictRequire Option enabled:
SSLOptions +StrictRequire SSLRequireSSL SSLRequire %{HTTP_HOST} eq "example.com" ErrorDocument 403 https://example.com
Using SSI on files with an .html extension
Parsing all .html files
DreamHost’s servers are configured by default to only parse files with an .shtml extension with server-side includes. If you ensure all your files that include other files (using SSI) are named "something.shtml" you won't have to do anything to get them to work.
However, some customers have transferred a site from a different server configuration where any .html file was parsed for SSI. It can be a difficult to rename all the files in a website, as well as fix any links between them. Because of this, DreamHost allows users to turn on parsing of ANY sort of file they'd like.
To do this, simply create a plain text file named ".htaccess" in the directory in which you'd like all files with a different extension to be parsed for SSI. Inside the .htaccess file, put this one line:
AddHandler server-parsed .html
That's it. Now any file ending in .html will have SSI run on it. DreamHost really does not recommend doing this, unless it is absolutely necessary. It adds some overhead to the web serving to parse in SSI as each and every request for an .html file (even ones that don't have any SSI in them) are slightly slower when you turn on this option. It's much better to just name the appropriate files with the .shtml extension.
Using XBitHack
Another way to accomplish this is to enable "XBitHack" via your .htaccess file by adding this line:
XBitHack on
Then, set the user execute bit on the .html file using either of the following commands:
chmod u+x yourfile.html
- -or-
chmod 744 yourfile.html
Miscellaneous
Forcing a file download
By default, if a text file (.txt) is requested, the contents of the file is shown in the browser and is not downloaded. This is because the default MIME type for .txt files specifies to show the files and not download them. However, you can change this by adding the following line:
AddType application/octet-stream txt
You can change the extension to anything you like such as mp3 or mov. Here is another example which does the same thing – any files ending in mov, mp3, jpg, or pdf are automatically downloaded:
<FilesMatch "\.(mov|mp3|jpg|pdf)$"> ForceType application/octet-stream Header set Content-Disposition attachment </FilesMatch>
Creating a 'site maintenance' message
If your site is going into maintenance, you can forward visitors to your site to a maintenance message automatically. First, you must create a file named 'maintenance.html' in your web directory. Then, add the following to your .htaccess file:
Options +FollowSymlinks RewriteEngine On RewriteBase / RewriteCond %{REQUEST_URI} !/maintenance.html$ RewriteRule .* /maintenance.html [L]
If you now visit the site, it automatically loads the contents of the maintenance.html file, but the URL does not change.
You can replace [L] with [R=307,L] if you prefer that the user see the URL change to example.com/maintenance.html. However, this is usually not what you want.