Skip to page content or skip to Accesskey List.
Search evolt.org
evolt.org login: or register

Work

Main Page Content

A Cheesy .htaccess Tutorial

Rated 4.22 (Ratings: 11) (Add your rating)

Log in to add a comment
(19 comments so far)

Want more?

 
Picture of AnthonyB

Anthony Baratta

Member info | Full bio

User since: July 09, 1999

Last login: October 25, 2006

Articles written: 12

... Slapped together from a few emails (or, what I learned from www.apache.org, plus banging my own head against the wall)...

Topics you will find in this article are:

A Few Important .htaccess Options

Apache uses the .htaccess files to customize the web server responses. If you are not experienced with .htaccess file, now is a good time to learn. They are "archaic" but useful. Make sure that your server will accept an .htaccess file overriding the default settings. Check with your ISP first.

Using NotePad or your favorite text editor (vi if you are an uber-monkey) create the following file:

Name = htaccess.txt (after FTPing the file over, rename it to .htaccess)

Options Includes ExecCGI
AddHandler cgi-script .cgi
DirectoryIndex index.html index.htm index.cgi
AddType text/x-server-parsed-html .html .htm .ssi

Save the file and FTP it to the directory you want the cgi script to be the index page. BIG NOTE: .htaccess files are inclusive and last option rules. What this means is that you can set up an .htaccess file within the root directory of your web server /web/sites/ <server> and it will be applicable to the rest of the downstream tree. If another .htacess file is downstream the two are "added" together. Any commands that are contradictory are not debated. The last one processed wins. So downstream .htaccess files would override any contradictory rules set previously. (Clear as mud?)

Now rename your script to index.cgi and move it into the target directory.

There are a lot of cool and fancy things you can do with the .htaccess file (this is where you start for password protecting a directory).

-- What the file means --

Options Includes ExecCGI

The Options directive controls which server features are available in a particular directory. Includes says do SSIs, ExecCGI says execute cgi scripts from within this directory. More Info:

http://www.apache.org/docs/mod/core.html#options

AddHandler cgi-script .cgi

AddHandler maps the filename extensions extension to the handler handler-name. More info:

http://www.apache.org/docs/mod/mod_mime.html#addhandler
http://www.apache.org/docs-1.2/handler.html

DirectoryIndex index.html index.txt index.cgi

The DirectoryIndex directive sets the list of resources to look for, when the client requests an index of the directory by specifying a / at the end of the a directory name. More Info:

http://www.apache.org/docs/mod/mod_dir.html#directoryindex

AddType text/x-server-parsed-html .html .htm .ssi

The AddType directive tells the Apache server to "parse" all the files with the listed extensions for SSI commands. More Info:

http://www.apache.org/docs/mod/mod_mime.html#addtype

(This can also be performed via the following command.)

AddHandler server-parsed .htm .html .ssi

More info:

http://www.apache.org/docs-1.2/handler.html

Auto Headers and Footers for Fancy Indexing

Did you know that Apache can put headers and footers on the pages it auto indexes??

If you do not have an index.htm(l) page in your sub-directory Apache sends a list of the files in that directory. Much like an FTP listing. (This is on usually by default and can be turned off with the command 'Options -Indexes' in a .htaccess file.)

However the page is not too fancy (even though they call it fancy indexing.) You can spruce up the page by customizing the header and the footer via the .htaccess file.

Put the following in the .htaccess file for that directory....

HeaderName filename ReadmeName filename

For example...when indexing the directory /web, the server will first look for the HTML file /web/filename.html and include it if found, otherwise it will include the plain text file /web/filename, if it exists. The file must be in the target directory - you can not reference a file from another directory (although you can "within" the used header/footer file. (ReadmeName is the footer file.)

Also - start your header file with BODY - you don't need to end your footer file with </body> or </html>

Lastly - I name your header and footer file with a '.' in the beginning. This will prevent the file from showing up on the directory listing. Putting a '.' as the first character in the name is a UNIX trick to make the file 'disappear'. e.g. I named my header and footer file '.download-header.html' and '.download-footer.html'. Therefore my .htaccess file looks like this...

HeaderName .download-header ReadmeName .download-footer

So no .html as the extension because Apache already adds that when it looks for the file.

So you can embed HTML and formatting in to the header and footer of an index of files. You can see my attempt at http://www.baratta.com/southpark/files - you can see a better attempt at http://soundamerica.com

Password Protecting a Directory

You need two files - one called '.htaccess' and the other any name you want/any location you have read/write access to. I call my web password files '.htpasswd' and put them in a directory under my home directory. If you use a directory off your home directory, make sure that the directory is 755 and the password file is 644, so the web server can see and use it.

e.g. password file is in /web/foo/home/bin-foo while the /web/sites/foo/members is the password protected directory.

Makes it harder to steal your password file.

OK create an .htaccess file with this stuff...

AuthName " <phrase the user sees in the login box>"
AuthType Basic
AuthUserFile /full/path/to/file/.htpasswd
require valid-user 

Of course put the .htaccess file in the directory you want password protected.

Now...cut and paste the following code into a file called make-password or something - chmod it to 700. (make sure that the path to PERL is correct)

This file will allow you to make and add password files without having to do much work.

(Apache comes with another program to do this, I use this code snippet because I've attached it to a few admin programs I use with Perl to make and change user passwords.)

#!/usr/bin/perl
if (scalar(@ARGV) < 2) {
print <<EOF;
usage: make-password <htpasswd file> <user> <password>
EOF
exit;
}

$salt="XX";
$file=$ARGV[0];
$key=$ARGV[1];
$value=$ARGV[2];

if ($file && $key && $value) {
$hash = crypt($value, "$salt");
open(DB, ">>$file") || die "Error: $!\n";
print DB "$key:$hash\n";
close(DB);
print "User $key added with password $value, 
encrypted to $hash\n";
exit;
}

+++++

Put the file in your home 'bin' directory. If your admin set you up right you should have a path to a bin directory in your path statement, even if the bin directory does not exist. (Check with the command 'env'.) Make the directory if it does not exist.

To make a new password file just type the following in the directory you want to create the password file.

make-password htpasswd file name> <user name> <password>

If htpasswd file does not exist it is created. You can use this command to add new names and passwords to the htpasswd file. To delete a name and password, just vi the file and 'dd' the line to delete it.

Fire up the browser and test. Should work.

Customizing Server Error Messages

You can customize your server's error message so your users are not struck with a stark bleeding white web page with a less than helpful message on it.

The standard errors generated are: 400, 401, 403, 404, 500,

400 = Bad Request. Usually a mangled communication between the browser and server.
401 = Authorization Required. If the user cancels a password request, this error is generated.
403 = Forbidden. If indexing is turned off, and/or the server can not show/access the directory.
404 = Page not found. It ain't there buck-o.
500 = Internal Server Error. Mostly likely a script bombed.

Just mockup some pages to explain the error message(s). Add your site navigation and styles so that they look like part of your site. Then add the following to your .htaccess file:

ErrorDocument 400 /path/to/error-400.html
ErrorDocument 401 /path/to/error-401.html
ErrorDocument 403 /path/to/error-403.html
ErrorDocument 404 /path/to/error-404.html
ErrorDocument 500 /path/to/error-500.html

Note 1: Make sure you call the error file or script based upon the 'root' of the web domain.

Note 2: Make sure you use hard references to all your images and links (versus relative references).

You can point all or some of the error messages to the same html file. Also you can invoke a script when the error is generated. That way you can dynamically generate the error message or run a 404 URL through an index and offer your visitors a choice of possible similar pages.

e.g.

ErrorDocument 404 /cgi-bin/error.cgi

Apache will have available to your script the following environment variables so that you can use them to generate info back to the browser:

REDIRECT_HTTP_ACCEPT=*/*, image/gif, image/x-xbitmap, image/jpeg
REDIRECT_HTTP_USER_AGENT=Mozilla/1.1b2 (X11; I; HP-UX A.09.059000/712)
REDIRECT_PATH=.:/bin:/usr/local/bin:/etc
REDIRECT_QUERY_STRING=
REDIRECT_REMOTE_ADDR=121.345.78.123
REDIRECT_REMOTE_HOST=ooh.ahhh.com
REDIRECT_SERVER_NAME=crash.bang.edu
REDIRECT_SERVER_PORT=80
REDIRECT_SERVER_SOFTWARE=Apache/0.8.15
REDIRECT_URL=/cgi-bin/buggy.pl

More info:

http://www.apache.org/docs/mod/core.html#errordocument
http://www.apache.org/docs/custom-error.html

Mutated into a life-size Dilbert doll, Anthony spends the days wedged into his replica of Cardinal Fang's Comfy Chair coding solutions to the most thorny of internet software problems.

Submitted by MartinB on July 11, 1999 - 04:50.

Excellent tutorial, Anthony. One wee question on customising the directory listings: Can you customise the icons the server uses for various filetypes?

login or register to post comments

Submitted by AnthonyB on July 11, 1999 - 13:02.

AddIcon path/icon.gif list of extensions e.g. AddIcon /path/to/binary.gif .bin .exe More Info: http://www.apache.org/docs/mod/mod_autoindex.html#addicon or http://www.apache.org/docs/mod/mod_autoindex.html#addiconbytype

login or register to post comments

Submitted by IanTheT on September 13, 1999 - 15:37.

One point: In the generic .htaccess file, you've added .html and .htm to the list of server-parsed document extensions. This is a Bad Thing. Better to add .shtml, and leave your normal documents unparsed. Otherwise, the server has to parse every single page before it sends it out. Unless, of course, every single page actually *does* use SSI.

login or register to post comments

Submitted by AnthonyB on September 13, 1999 - 16:08.

Not to start a religious war - but based upon the stress testing I've done, the hit you take on parsing all pages for SSI's is minimal to negligable on your average server. Unless you get SlashDot like traffic, SSIs are a great and cheap way to add some dynamic content to your site. If you are approaching Slashdot type traffic - you should be using something like PHP or ASP. In fact badly optimized graphics do more to pull your site load times down than parsing every page.

login or register to post comments

SSI performance hit

Submitted by MartinB on November 21, 2001 - 11:22.

SSIs (including XSSI) have a lower performance impact than the equivalent CGI - mostly because you don't have to crank up the Perl/PHP/whatever interpreter. If you can use SSIs for server side scripting, do use them.

login or register to post comments

Peformance Hit Redux....

Submitted by AnthonyB on November 21, 2001 - 23:01.

Martin, you are correct if the interpretter is not already loaded into memory. mod_PHP and mod_Perl both overcome the "overhead" of loading and unloading the script interpreter. Both fly at processing scripts when already in memory.

The caveat stands - use the best tool for the job.

P.S. I can't believe we are even discussing this "olde" article. That just cracks me up.

login or register to post comments

Hide dinamic pages

Submitted by fiorito on December 26, 2002 - 08:22.

Is there any way to make a ".php" script work like:
http://www.domain.com/articles/3
instead of:
http://www.domain.com/articles.php?id=3
Using .htaccess ?

login or register to post comments

pointing ReadmeName at a .php file???

Submitted by aRagStain on August 25, 2004 - 08:57.

Is it possible to point ReadmeName at a .php file (rather than html)??? I havn't figured a way out yet ("ReadmeName .easyfooter.php" doesn't work). everything else is working great, thanks for the tute :)

login or register to post comments

pointing ReadmeName at a .php file???

Submitted by AnthonyB on August 25, 2004 - 09:30.

Here's the official information:

http://httpd.apache.org/docs/mod/mod_autoindex.html#headername

"Filename must resolve to a document with a major content type of "text" (e.g., text/html, text/plain, etc.). This means that filename may refer to a CGI script if the script's actual file type (as opposed to its output) is marked as text/html such as with a directive like:

AddType text/html .cgi"

Also:

"Apache 1.3.6 and earlier: The module first attempts to include filename.html as an HTML document, otherwise it will try to include filename as plain text."

Re: Clean URLs with PHP here's a great Tutorial:

http://www.evolt.org/article/Making_clean_URLs_with_Apache_and_PHP/18/22880/

login or register to post comments

pointing ReadmeName at a .php file???

Submitted by aRagStain on August 25, 2004 - 14:19.

AnthonyB, thanks for the advice ... still tho, I seem to be causing a conflict with my htaccess settings.

I managed to get ReadmeName to find my .easyfooter.php as a text document with this line:

AddType text/html .php

but then the server doesn't execute the file as php code, it displays only the html content of the file.

am I trying to do something impossible, or is there a way to tell apache to execute php files even though they are of the type text/html??? thanks again for any advice!!!

login or register to post comments

pointing ReadmeName at a .php file???

Submitted by AnthonyB on August 25, 2004 - 15:28.

I don't see any examples of using scripts with HeaderName. You might want to canvas the PHP forums and see if anyone else has attempted this.

login or register to post comments

stuck

Submitted by nato1138 on March 15, 2005 - 12:51.

This is not working for me. I have an ftp dir that uses the headerName beautifully. But it does not work for the sub-directories. And it should. .htaccess files are supposed to unless a new one cancels out an option higher up on the tree. Any solutions????/ Thanx

login or register to post comments

re: stuck

Submitted by AnthonyB on March 15, 2005 - 13:13.

How are you calling the headerName in your .htaccess file. It could be that it's not finding it because it's a relative reference instead of a hard reference? What version of Apacher are you using? 1.3.x or 2.x?

login or register to post comments

stuck some more

Submitted by nato1138 on March 15, 2005 - 13:27.

I am running apache 2.X, and i am simply calling the header in this manner... #.htaccess headerName myFile in my http.conf I have set up an alias for my ftp dir. #httpd.conf alias /ftp/ "/var/ftp/" Options Indexes MultiViews AllowOverride ALL Order allow ...(all that good stuff)....... Relative/hard>>>?? Can you explain, thanx, n

login or register to post comments

re: stuck some more

Submitted by AnthonyB on March 15, 2005 - 13:37.

Try putting the whole path in the .htacess file:

/ftp/myFile

If you just put in myFile, when it gets to a subdirectory the web server is going to look "local" to where it's at, which is not were the file lives.

http://httpd.apache.org/docs-2.0/mod/mod_autoindex.html

Both HeaderName and ReadmeName now treat Filename as a URI path relative to the one used to access the directory being indexed. If Filename begins with a slash, it will be taken to be relative to the DocumentRoot.

Example

HeaderName /include/HEADER.html

login or register to post comments

Re: Perl script example

Submitted by Douglas Clifton on March 15, 2005 - 13:49.

Using the same 2 character salt for all your encryptions is not a real good idea.

Here's a nice little Perl script I wrote awhile back, someone may find it useful.
Note: depending on the Perl version you're using you may not need to seed the generator, but it won't hurt to do so anyway.

#!/usr/bin/perl

# pwg -- generate a random password and/or encrypt

use File::Basename;
$p = basename $0;

$usage = < Generate random pwd
           -l N     -> of Length N, default is 8
           -e [pwd] -> Encrypt pwd with random 2 character salt
USAGE

use Getopt::Std;
getopts('gl:e:', \%ops);

die $usage unless %ops;

srand;

# restrict plaintext passwords to alphanumeric characters
# we should probably add at least a few punctuation chars
# to foil the brute force kiddies

@c = ('A'..'Z', 'a'..'z', 0..9);

# generate random password, possibly of length N

if (exists $ops{g})     {
    $l = defined $ops{l} ? $ops{l} : 8;
    $pwd = join '', @c[map{rand @c}(0..--$l)];
    print $pwd, "\n";
}

# encrypt a password using random 2 character salt

if (exists $ops{e})     {
    $pwd = $ops{e} if defined $ops{e};
    die $usage unless $pwd;

    # period and slash are okay here

    push @c, ('.', '/');
    print crypt($pwd, join('', @c[map{rand @c}(0, 1)])), "\n";
}

__END__
pwg

login or register to post comments

re: stuck some more

Submitted by nato1138 on March 16, 2005 - 06:07.

The full path, although this makes sense, is helpful when my directory is actually in the document root. I have aliased a directory not in the doc root--/var/ftp-- This seems to be the issue. Is there a workaround? Would a wildcard in http.conf help at all in the directory tag? Nothing seems to work.
n

login or register to post comments

re: stuck some more

Submitted by AnthonyB on March 16, 2005 - 08:01.

What path would you type in from the browser to get to your HeaderName file? That is what they mean by URI path relative.

login or register to post comments

protecting from download

Submitted by marmarko on July 20, 2007 - 02:29.

i've been trying to figure this one out for a while. maybe you guys can help. i'm trying to protect mp3 files from being downloaded, but at the same time i need to be able to stream them from a flash player on the site. any ideas?

login or register to post comments

The access keys for this page are: ALT (Control on a Mac) plus:

evolt.orgEvolt.org is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.