This wiki is for the exclusive use of my friends and colleagues. Account creation and anonymous editing have been turned off.

If you are a friend or colleague of mine, and would like to participate in this project, please send me a message.

If you find these pages useful, please donate to help cover server costs. Thanks!

Htaccess Techniques

From OdleWiki
Revision as of 18:01, 6 March 2016 by Kenneth John Odle (talk | contribs) (Initial edit)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Contents

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>

Denying access to "hidden" 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:

Custom error pages

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:

mod_deflate

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>

Filter Documentation.

Generally safe options to add are:

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.

Template:Note2

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.

  1. Create an .htpasswd file in the directory you wish to password protect.
  2. Create this file using the htpasswd utility. For the first user, say user1, run the following:
    htpasswd -c /home/username/example.com/.htpasswd user1
  3. Enter the password for the user. This creates a password for a user named 'user1'.
  4. Run it again (without the -c option) for any other users you wish to allow access to your directory.
  5. Set the permissions on this file to 644.

View the following page for further information:

Apache Authentication HowTo

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

Template:Note2

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.

See also