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