***************************************************************************
* Guide to Installing & Configuring Apache *
* by fugjostle *
* *
* - V.0.1.beta - *
* *
* Questions? Comments? Email: fugjostle at g0tr00t.net *
***************************************************************************
--[Introduction]
This guide is intended to get you up and running with Apache as soon as
possible. This is not an indepth treatment of the Apache configuration so
for a full coverage of Apache and its capabilities look at:
http://httpd.apache.org.
The document is currently a little messy and has a to-do list that you
cannot imagine. Check back soon for the updated version.
So what is this 'Apache' thing? I hear you say... well, the Apache Group
heavily patched the NCSA httpd server when its development stopped. This
new server became known as 'a patchy server', and is now the most prevalent
http server on the web.
--[Getting the server]
Surf over to http://www.apache.org/dist/httpd/ and download the latest
version. At the time of writing the current stable version is 1.3.23.
Get a copy of the following file:
apache_1.3.23.tar.gz
On my system I always place the downloaded files in /tmp and will extract
the source into a build directory in my home directory:
[fug@fuggles.net]$ cd ~
[fug@fuggles.net]$ gunzip /tmp/apache_1.3.23.tar.gz
[fug@fuggles.net]$ tar xvf /tmp/apache_1.3.23.tar
or
[fug@fuggles.net]$ cd ~
[fug@fuggles.net]$ tar zxvf /tmp/apache_1.3.23.tar.gz
I've now uncompressed the files and I'm ready to install. This is the point
where you would decide what additional modules you want to compile into
Apache and which you want to remove. This is a bit more advanced and we
will look into it later.
--[The Basic Installation]
Let's install the default server but before we do, lets add in a bit
of security. I'm not a big fan of security through obscurity but the
following method will stop automated scanners identifying my server and
version.
Open up the 'apache_1.3.23/src/include/httpd.h' file in a file editor such
as VI. Find the following two define statements:
#define SERVER_BASEPRODUCT "Apache"
#define SERVER_BASEREVISION "1.3.23"
Edit these to replace 'Apache' with 'FugServ' and the version number with
'1.0.2' or something you like. When the evil hax0r looks at the HTTP
response's from your server she will see "Server: FugServ/1.0.2".
I'll create a shell script now... this allows me to manage my command line
parameters passed to the 'configure' script. You'll find that your command
line can become two or three lines long and you always make a mistake.
This not only simplifies the process but acts as a good reminder to a
previous install.
I'll create 'apache_config' in my build dir '/home/fug/build/apache_1.3.23'
#! /bin/bash
# Config Script for Apache
./configure --prefix=/usr/local/apache_1.3.23
The '--prefix' tells the configure script where we want to install Apache.
The default is '/usr/local/apache'. I include the version number so I can
keep track of concurrent versions. This way I can install the next version
and if it fails I can go back to the old version.
Now I make my config script executable:
[fug@fuggles.net]$ chmod 0744 apache_config
What the hell :-) Let's configure Apache:
[fug@fuggles.net]$ ./apache_config
and in a few moments the configuration process should be finished and your
ready to 'make' the files ready for install:
[fug@fuggles.net]$ make
[fug@fuggles.net]$ su
password: ******
[root@fuggles.net]# make install
Well done!! You've just installed Apache onto your box. Let's start it and
see if it runs:
[root@fuggles.net]# cd /usr/local/apache_1.3.23/bin/
[root@fuggles.net]# apachectl start
'apachectl' is a tool for starting, stopping and restarting Apache. Enter
the command on its own for a list of possible options. Now open your web
browser and surf over to 'http://localhost' and you should see the Apache
welcome message.
You now have a your web server running. Let's stop the server and do some
customisation work:
[root@fuggles.net]$ apachectl stop
--[The Configuration File]
When Apache starts it reads the /usr/local/apache_1.3.23/conf/httpd.conf
file which is used to set runtime options such as the location of the
documents its going to serve. In the 'conf' directory you should have the
following two files:
httpd.conf
httpd.conf.default
These files are identical, so delete 'httpd.conf' and we will create a
new one. We'll add some standard issue stuff and then as you work through
this document you can decide what else to add.
MinSpareServers 5 <-- Min # of waiting servers
MaxSpareServers 10 <-- Max # of waiting servers
MaxClients 256 <-- Max # of clients to server at one time
StartServers 5 <-- # of servers to start
Timeout 300 <-- Timeout period for connections (in seconds)
This is the first entry into our 'httpd.conf'. To shed some light on the
above directives then I should explain how Apache works. Apache runs as
root and when a request arrives for a webpage then Apache forks off a child
process that runs under some no-access account and this child process will
handle the request.
The process of forking off a new child process can take some time and so
in an effort to speed things up the above directives get Apache to produce
some spare servers that sit there waiting for a connection. Once the
connection has been completed the server dies and Apache creates another
spare server to replace it.
For now we will use the default values and at a later stage you should play
with the values and see what works for you and your site.
There's one thing we need to do before going any further. We need to create
a user that the server can run as. For this example I'm going to use 'webuser'
and the account is going to be a member of 'webgroup':
[root@fuggles.net]# groupadd -g 200 webgroup
[root@fuggles.net]# useradd -m -g webgroup -d /webpages -c "Apache" webuser
[root@fuggles.net]# passwd websuser
Notice I've used '/webpages' as the home directory, I'm going to use this as
my document root for the web pages. Now we are ready to add a few more lines
to our httpd.conf file:
User webuser <-- The user the children will run as
Group webgroup <-- The group the children will run as
ServerName fuggles.net <-- The server name sent to the client
ServerAdmin fug@fuggles.net <-- This is the admin's email used in error msg's
ServerRoot /usr/local/apache_1.3.23 <-- Location of the server files
ServerType Standalone <-- Tells Apache not to run via inetd
DocumentRoot /webpages <-- Location of the HTML files
Listen 80 <-- The port the server is going to listen on
PidFile log/httpd.pid <-- Location of the Process ID for the server
TransferLog log/access_log <-- Location of the requests log
ErrorLog log/error_log <-- Location of the error log
KeepAlive On <-- Allows more than one request per connection
MaxKeepAliveRequests 100 <-- Max # of persistant conections
KeepAliveTimeout 15 <-- # of seconds to wait for subsequent requests
Believe it or not, you now have a httpd.conf file that will run your server.
You can test the syntax of the file by using the following command:
[root@fuggles.net]# apachectl configtest
--[How to Configure Logging]
By default, all access/requests are logged into the Transfer log in the
following format:
192.168.1.10 - - [11/JAN/2002:19:52:42 -0400] "GET /index.htm" 200 1687
^ ^ ^ ^ ^ ^ ^
| | | | | | |
Client Name | | | | | |
or | | System Time Command Issued | |
IP Address | | of the Request to the Server | |
| | / |
/ \ / Bytes
/ \ / Transfered
Identity of Supplied Status
the User Username Code
All error's are sent to the error_log. This is the first place you should
look when your CGI's don't work ;-)
You can customise the format of log using the 'LogFormat' directive. The
default log format statement is:
LogFormat "%h %l %u %d \"%r\" %s %b"
The table below identifies some of the tokens you can use for the
'LogFormat' statements:
b: Bytes Transfered a: Remote IP
f: File Requested l: Login Name
h: Remote Hostname p: httpd Port
P: Process ID t: Time
r: Request U: URL Requested
s: Status Code d: Date
u: Remote Username {var}i: Value of 'var' in the header
You can also create a custom log using the 'CustomLog' directive:
CustomLog log/my_log "%h %l %u %d \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" "
This will send a more detailed log to 'my_log'. This is fine and dandy but
what can I do with this? Well, I have a friend who has a webpage full of
complex graphics. The page is set to refresh every few minutes and his logs
get hammered by '.gif' requests. So let's get all advanced and help him with
the problem. The following addition to the httpd.conf will not log requests
for '.gif' or '.css' files and I've added a bit extra that will allow me
to log '.php' requests into a seperate file:
SetEnvIf Request_URI \.gif$ unwanted
SetEnvIf Request_URI \.css$ unwanted
SetEnvIf Request_URI \.php$ phpstuff
LogFormat "%h %l %u %d \"%r\" %s %b" access
CustomLog log/access_log access env=!unwanted
CustomLog log/php_log access env=phpstuff
--[Enabling Server Side Scripting]
----[1. Common Gateway Interface]
Common Gateway Interface (CGI) processing is controlled by the 'Options'
directive. CGI can be enabled/disabled by the following entry in the
httpd.conf file:
Options +ExecCGI <-- Enables CGI
Options -ExecCGI <-- Disables CGI
Once enabled you have three directives at your disposal: ScriptAlias,
AddHandler and SetHandler.
'ScriptAlias' maps '/cgi-bin' to a specific location and anchors the use of
CGI to that directory:
ScriptAlias /cgi-bin /webpages/cgi-bin
using this directive, anyone who goes to http://myserver/cgi-bin/test.cgi
will be running test.cgi that is in '/webpages/cgi-bin'.
'AddHandler' allows the processing of pre-defined extensions as CGI scripts
from the document root:
AddHandler cgi-script .cgi
'AddHandler' applies to the entire site and shouldn't really be used. A better
alternative is the 'SetHandler' directive. This directive allows you to limit
CGI execution to a certain directory and domain. The following example is a
block directive - don't be put off - a block directive is just a way of
grouping directives to a specific location, directory or file:
order deny,allow
allow from mydomain.com
deny from all
SetHandler cgi-script .cgi
[Don't worry about the 'order deny,allow' stuff... that comes later]
----[2. Server Parsed HTML]
Server Side Includes (SSI) are processed by Apache before it sends the HTML
to the client. To enable SSI you need to use the following 'Options'
directive:
Options +Includes
Now you need to tell Apache how to recognise SSI files and what it should
do with them:
AddType text/html .shtml <-- defines file type and extension
AddHandler server-parsed .shtml <-- defines which built-in parser is used
SSI is a web technology that you should be very wary off. SSI can be used
to execute a CGI, shell scripts or shell commands. For example, consider
the following SSI:
You can extend the previous 'Options' directive to make SSI a little more
secure by using:
Options +IncludesNOEXEC
This option enables all the SSI except the 'exec' command. The use of SSI
should be disabled unless you really need it. If you are going to use SSI
then ensure that you validate all user input to strip any user defined SSI.
----[3. Java Applets and Servlets]
Java applets are delivered to the client to be executed locally. This is
achieved by sending the applet as an octet stream, similar to the way
images are sent. In order to allow applets to be used you should edit the
'mime-types' file in the 'conf' directory. In the 'application/octet-
stream' section you should add the extension 'class'.
If want to run Java Servlets or Java Server Pages (JSP) then I would
recommend looking at Jakarta-Tomcat. This is a collabortive project from
Sun and the Apache Group focusing on Java-based web applications. Just
follow the link from www.apache.org.
--[Compiling Apache with Additional Modules]
It the next version of this tutorial I will cover installing mod_perl,
SSL and PHP. Until then I'll quickly go through enabling of Apache
modules. You can view the installed modules by using the 'httpd' binary
with the '-l' option.
[root@fuggles.net]# cd /usr/local/apache_1.3.23/bin
[root@fuggles.net]# httpd -l
You should be presented with a list of installed modules. Some of these
modules may not be needed and can be disabled using the following line
in our 'apache_config' script (Remember the config file we created?):
--disable-module=mod_name
Lets edit the 'apache_config' file and add-in another module:
#! /bin/bash
# Config Script for Apache
./configure --prefix=/usr/local/apache_1.3.23 \
--enable-module=info
Running this script and re-making the server will produce a new binary
with the mod_info module compiled into it. Now you need to add an entry
into your config file to use the module:
SetHandler server-info
There is another module compiled by default that I want to use for an
example in the next section. This is the mod_status module and lets
enable that next:
SetHandler server-status
The SetHandler directive tells the server that any requests for the URL
/status will be handled by the server-status module. Ok, lets restart
the server to get it to read the new config file.
[root@fuggles.net]# apachectl restart
Go to the following URL's to ensure that its all worked:
http://localhost/status
http://localhost/info
--[Building Access Control]
As you can probably see from the last section there is a definate need
for access control. You don't want anyone being able to view the status
and info pages. So what can you do? No problemo... we can use access
control to limit who can see what. We will use the 'Location' directive
blocks that we created in the last section and add some elements of access
control to them.
SetHandler server-status
allow from 127.0.0.1
allow from admin1.fuggles.net
deny from all
order deny,allow
Lets break this down line by line. The allow statement tells the server
who can see this 'location'. The allow statement can take different
forms, for example:
allow from all <-- everyone
allow from mydomain.com <-- anyone from mydomain.com
allow from 10.1.10.100 <-- IP = 10.1.10.100
allow from 10.1.10 <-- anyone with IP = 10.1.10.0-255
allow from 10.1.0.0/255.255.192.0 <-- as above but using CIDR
The deny statements take the same format. The order you define the deny
and allow statements is off no consequence. What is of major importance is
the 'order' statement. This tells Apache how to process the allow and deny
statements. If you 'deny,allow' then all the denies are processed first
and then the allows are processed. So in our example everyone is denied
except those that we explicitly allow (localhost and admin1).
'order allow,deny' is pretty much the opposite. Everyone is allowed unless
they are explicitly denied.
The allow/deny directive can be used for and blocks as
well as the Blocks. Lets secure the /info page as well:
SetHandler server-info
deny from all
allow from 127.0.0.1
order deny,allow
Pretty straight forward? Here is something a bit more advanced. Lets only
allow people using Netscape 4.07 accessing the '/webpages/cgi-bin'
directory using the directive 'BrowserMatch':
BrowserMatch ^Mozilla/4.07 nutscrape=yes
deny from all
allow from env=nutscape
order deny,allow
This is just to give you an idea of what is possible. Have a look through
the httpd documentation to get some more ideas of how you can use this and
other techiniques.
When we installed Apache the 'mod_auth' module was installed by default.
This gives us some flat file authentication mechanisms. Before we continue
lets create a directory that we are going to secure using 'mod_auth'.
[webuser@fuggles.net]$ cd /webpages
[webuser@fuggles.net]$ mkdir secure
First thing we have to do is create a password file for all the users.
Apache comes with a tool called "htpasswd". With this tool you can create
a password file and edit it.
[root@fuggles.net]# cd /usr/local/apache_1.3.23
[root@fuggles.net]# mkdir passes
[root@fuggles.net]# chown webuser.webgroup passes
[root@fuggles.net]# chmod 744 passes
Ok... we have just created the 'passes' directory, changed the perms and
changed the ownership to that of the webserver. Now its time to create
the password file.
[root@fuggles.net]# cd /usr/local/apache_1.3.23/bin/
[root@fuggles.net]# htpasswd -c /usr/local/apache_1.3.23/passes/.priv_file fugjostle
New password: ********
Re-type new password: ********
Adding password for user fugjostle
(traddionally the .priv_file is called .htpasswd but who cares)
Right... the password file has been created with the '-c' option and a user
has been added to the file [fugjostle]. Lets add another user to the file
but DO NOT USE THE '-c' OPTION. This will re-create the file and overwrite
the password file.
[root@fuggles.net]# htpasswd /usr/local/apache_1.3.23/passes/.priv_file ReDeeMeR
New password: ********
Re-type new password: ********
Adding password for user ReDeeMeR
Voila! We have added another user to our file. Now I just need to change
the owner and permissions of the newly created '.priv_file' so that the
server can use it.
[root@fuggles.net]# cd /usr/local/apache_1.3.23/passes
[root@fuggles.net]# chown webuser.webgroup .priv_file
[root@fuggles.net]# chmod 700 passes ,priv_file
Now we have a password file its time to tell the server when to use it.
AuthUserFile /usr/local/apache_1.3.23/passes/.priv_file
AuthName "Secure Zone"
AuthType Basic
Require valid-user
You have just secured the URL '/secure'. Anyone attempting to get access
to that URL via the browser will get a '401 Unauthorised' message from the
server. The client's browser will usually prompt for a username/password
on reciept of the message and re-submit the request to the server.
Lets break it down and understand this block of directives. 'AuthUserFile'
tells the server where to look for the password file. 'AuthName' defines
the text that appears in the browser window. For example you could use
something like:
AuthName "Unauthorised Access Forbidden"
'AuthType' tells Apache how to handle the passwords. Your pretty much stick
with "Basic" as this is supported by all browsers. You could use "Digest"
which uses MD5 instead but no browsers support this :-(
Please Note that using "Basic" means that the username and password are
combined like this:
username:password
and then are encoded using Base64 before sending to the server. Its not
the height of security. If security is important and you really want to
use "Basic" authentication then look at using it over SSL instead.
The 'Require' directive actually enables the authentication. You can
specify three formats for this statement.
Require user [list of users] --> Require user fugjostle, ReDeeMeR
Require group [list of groups] --> Require group webmasters, cgiadmins
Require valid-user
"valid-user" means anyone who is defined in the AuthUserFile. The "user"
directive allows you to specify only specific people in the AuthUserFile.
To use the "group" directive you need to create a groups file. This is a
plain text file that contains the names of the group members:
webmasters: fugjostle, ReDeeMeR, think12
cgiadmins: The_Itch, Enstyne, nsh
To use this file you need to add another directive the Location block:
-->AuthGroupFile /usr/local/apache_1.3.23/groups/.mygroups
AuthUserFile /usr/local/apache_1.3.23/passes/.priv_file
AuthName "Secure Zone"
AuthType Basic
Require group webmasters
(I'm not covering actual filesystem permissions which return 403 forbidden
messages if they are restrictive... mainly cause I can't be arsed)
Ok... we are slowly getting there. The last access control mechanism I'm
going to cover is the '.htaccess' file.
Let's set the scene, the lights are low, the candles are burning... erm,
sorry, thats the wrong scene. Lets start again... You want to give people
access to your server and allow them to host there own webpages. Very much
like an ISP would. These users want to secure their directories and keep
some of the information private. This is where '.htaccess' files come in.
'.htaccess' files contain Apache directives which basically grants an
extension of the webmastery to anyone who has access to edit them. First
things first, lets break with traddition and change the name of our
'.htaccess' and call it '.config'. We define the name of the '.htaccess'
file in the httpd.conf file with the 'AccessFileName' directive:
AccessFileName .config
I'm not going to go into too much detail because unless you want to give
users control over the configuration of the server then you don't really
need '.htaccess' and you should just use the httpd.conf to set directory
controls. For those of you who just need to know then ok... A typical
'.htaccess' can look something like this:
ErrorDocument 404 /errors/ReD404.htm
ErrorDocument 403 /errors/ReD403.htm
ErrorDocument 401 /errors/ReD401.htm
AuthType Basic
AuthUserFile .htpasswd
AuthName "ReD's Private Area"
Require user ReDeeMeR
DirectoryIndex red.php red.html
It's wise to prevent the server giving people the .config (.htaccess) file
so I would suggest preventing it using the following directive:
order allow,deny
deny from all
If your going to stick with the tradditional names like '.htpasswd' and
'.htaccess' the try the following restriction:
Order allow,deny
Deny from all
When the server finds an .htaccess file (or whatever you call it) it needs
to know which directives declared in the file can override directives
in the httpd.conf. This is controlled by the directive 'AllowOverride'
declared in the httpd.conf.
AllowOverride None <-- Ignore the .htaccess file
AllowOverride AuthConfig <-- Allows the authorisation directives
AllowOverride FileInfo <-- Allows document type directives
AllowOverride Indexes <-- Allows dir index directives
AllowOverride Limit <-- Allows host access directives
AllowOverride Options <-- Allow dir features directives
If you are like me and think screw the users then you can rest assured that
you'll never be ISP but heh, who cares! If you want to stop '.htaccess' being
used then place the following in your httpd.conf:
AllowOverride None
--[Conclusion]
Well that's it. I hoped you enjoyed this and hoped it helped. This is still
in its beta stage and will be updated soon. Keep checking back for the next
version. If you have any feedback or questions then you can get hold of me
at the following addy: fugjostle at g0tr00t.net (remove the anti-spam first)
***************************************************************************
Greetz to: ReDeeMeR, BarnseyBoy, Reeferman, gabbana, Wang, Enstyne, munk,
[502BOP], Muad_Dib, Macster, n0face, palmito, kph, Homicide, Col,
Axem, Booto, _Penguin, nsh, Chawmp, shad, think12 and everyone
in #CA who are way too numerous to mention.
***************************************************************************