05- Apache on CentOS

Apache 2.2.3 on CentOS 5.5

Starting Apache

To do it once, from the script

# /etc/init.d/httpd start

To ensure it always starts, navigate System -> Administration -> Server Settings -> Services and enable httpd. This can be done manually via chkconfig.

In either case, be sure to open the firewall: navigate System -> Administration -> Security Level and Firewall.


To find the version of apache, run

# httpd -v

This document describes the 2.2.x series for Apache, from CentOS 5.5. Other versions of Apache include the 1.x series and the 2.0.x series, which have slightly different internal structures.


Apache comes with its own documentation. Suppose that your web server is located at “webserver.tu”. Then, at least initially, the apache manual is accessible at http://webserver.tu/manual

Verify this, by loading the manual- both from a browser on the server itself, and from a second browser on a different host.

Apache Structure

Apache is structured around a series of modules, which can either be compiled into the program or added dynamically. To see the compiled modules, run

# httpd -l

How many complied in modules are present in your system?

To see the dynamically loaded modules, we will need to look at the configuration file- later!

Directories and files

These are the CentOS defaults; other systems use variations on this theme.

        httpd.conf      Main configuration file
    conf.d/             Subdirectories for specific tasks
        manual.conf     Should the apache manual be served?
        php.conf        Set up PHP for apache; not the same as php.ini
        ssl.conf        Configure SSL
    logs ->              link to /var/log/httpd/
    modules ->           link to /usr/lib/httpd/modules/
    run ->               link to var/run/
    cgi-bin/            directory for CGI script
    error/              HTTP error messages in multiple languages
    html/               Root directory for web
    icons/              Collection of public doman icons
    manual/             http://localhost/manual
    usage/              http://localhost/usage

Because of the size and complexity of this system, and because we have only a limited time to devote to this topic, we will only cover some of the functionality available in the system. You are encouraged to explore.

Tour of the configuration files


Line 57 sets the root directory for the server (not the web site(s))

ServerRoot “/etc/httpd”

Read http://localhost/manual/mod/core.html#serverroot

Line 134 sets the IP addressed and port(s) that apache is litening for

Listen 80

The default is to listen to all IP adresses of the host, on port 80. See later in this document for details on how to set your linux system up to use multiple interfaces.

Read http://localhost/manual/mod/mpm_common.html#listen for details on the directive.

Lines 148++ load various dynamic modules.

LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule auth_digest_module modules/mod_auth_digest.so

How many dynamic modules does Apache load? Does this explain why they were not listed earlier in our discussion of compiled modules?

To find out more about these modules, read http://localhost/manual/mod.

Line 210 specifies additional configuration files to read

Include conf.d/*.conf

See http://localhost/manual/mod/core.html#include

Lines 231-232 set the user and group for the server

User apache
Group apache

See http://localhost/manual/mod/mpm_common.html#user

Line 281 sets the root directory for the web site (not the server)

DocumentRoot “/var/www/html”

See http://localhost/manual/mod/core.html#documentroot

Apache sets policies on a directory-by-directory basis; moreover these directory directives can overlap. Read the documentation at http://localhost/manual/mod/core.html#directory

What is the default policy of Apache towards a directory?

Will a default Apache (i.e. not the customized CentOS version) serve the file /etc/passwd? Will it serve the file /etc/shadow? Will the default Apache follow a link in the file system? Does this change your answer to the previous question?

Read the documentation at http://localhost/manual/sections.html. What happens if two different <Directory> directives apply to a directory? Which takes precedence?

The first <Directory> directive occurs on lines 291-294. What does it do?

Lines 306-335 form another <Directory> directive. What is the directory to which they refer? Create a valid html file in that directory. Verify that it is served. Create a symlink to /etc/passwd and put it in the directory. What happens when that file is requested? Create a hard link to /etc/passwd and put it in the directory. What happens when that file is requested? Repeat the previous with /etc/shadow. Explain your observations. [Be sure to investigate any results from SELinux!]

Lines 306-335 is the <Directory> directive for the document root for the web server. Note that the syntax for the options for the <Directory> directive are not described at http://localhost/manual/mod/core.html#directory Instead, look at http://localhost/manual/mod/core.html#options to see the meaning of the options.

What are the default options for Document Root? What are the access controls for Document Root? See http://localhost/manual/mod/mod_authz_host.html for details of the syntax.

If the Allow from all line is removed, what is the default access policy for the server? Verify this.

Lines 349-364 by default turn off the use of directories for individual users. See http://localhost/manual/mod/mod_userdir.html and see also http://localhost/manual/howto/public_html.html

Enable user directories, but only for one user. To do so for the user named (eloquently, I think) user, modify these lines to include:

UserDir disable
UserDir enabled user

Why is this approach preferred over enabling user directories for all users?

Set the directory that is to be shared to be public_html by uncommenting the line

UserDir public_html

If a request is made of the server for the file http://server/~user/dir/page.html where in the file system should that file be located? Create this directory and this file. Test to see if the server serves your file. It didn’t? Huh. What are the permissions of the directory /home/user? What permissions are necessary so that another user (say the user apache from group apache) can traverse this directory? How about we make that change! What are the permissions for the directory and the file for your web page? Test again! How can user directories on a server be used by an attacker to determine the users of a computer?

Lines 370-381 are the <Directory> directive for the use of directories by individual users.

To understand the syntax for the <Limit> directive, see http://localhost/manual/mod/core.html#limit, while to understand the syntax for the <LimitExcept> directive, see http://localhost/manual/mod/core.html#limitexcept

What HTTP methods are allowed for the public user directories? What HTTP methods are not allowed for the public user directories?

Line 391 determines what file will be served if the user asks for a directory.

Line 398 sets the default name for directory-by-directory additional configuration files. For details on how this file is used, see http://localhost/manual/mod/core.html#accessfilename

Lines 404-407 prevent any files that start with the characters .ht from being served See http://localhost/manual/mod/core.html#files for documentation on the Files directive. If you want to, know more about regular expressions, go online- just remember that (1) Apache uses PCRE and (2) “Some people, when confronted with a problem, think ‘I know, I’ll use regular expressions.’ Now they have two problems.”

Line 472 sets the location of the error log.

ErrorLog logs/error_log

Note that this is relative to the root directory for Apache configuration (/etc/httpd) and should now explain why that directory has a symlink from logs to /var/log/httpd.

See http://localhost/manual/mod/core.html#errorlog for details; notice also that the log system can be set to use syslog.

Line 479 tells the server to log only at the level of warn or higher

LogLevel warn

See http://localhost/manual/mod/core.html#loglevel for the details.

Lines 485-514 set up the access logs for the system; these will be discussed in some detail below.

Line 524 tells Apache to include information about the current server version when returning an error message. See http://localhost/manual/mod/core.html#serversignature

Lines 539-547 set up an alias for the icons directory. View http://localhost/icons/.
(The trailing / is necessary.) Note the list of icons- even though there is no icons directory in document root- the alias command created it.

If an alias points outside of documentroot, permissions need to manually set on the directory. Aliases are quite powerful- see http://localhost/manual/mod/mod_alias.html

Line 564-575 sets up an alias for CG scripts; this alias is similar to the alias described above. To practice with a CGI script, create the file test.pl with the following content:

print “Content-type: text/html\n\n”;
print “This is a cgi script\n”;

Place the file in the CGI directory, and make it world-executable.

The first line tells the system how to execute the file. The second sets up the headers (and it needs BOTH newlines). The rest- well you can have it do whatever you want at that point. Note that this is code that is being executed by the server, on the server. Then http://localhost/cgi-bin/test.pl will execute the script and return the result.

It is possible to set up per-user CGI script directories if individual users have their own web directories. See http://localhost/manual/howto/cgi.html for more on CGI scripting. See http://localhost/manual/mod/mod_alias.html#scriptalias for more on the syntax for ScriptAlias

There is more to the file, but it is of lesser importance than the above, and we do nto have time for the discussions.

This is used to configure SSL on the server. We will discuss this in detail later when we cover SSL.

Note that this file is automatically included in the Apache configuration at line 210 of /etc/httpd/httpd.conf, where the directive

Include conf.d/*.conf

exists. Note that the structure of this include statement only includes files that end in “.conf”. Because many text editors automatically create backups of files, if you are not careful with this directive you can end up including both the original and the backup file, duplicating some statements and causing no end of hassle.

The file manual.conf is an alias and a directory directive to allow Apache to display the maunual. This is an allow from all- so the user does not have to be on localhost.

You can disable the manual by editing this configuration file.

This configures how Apache interacts with perl on the server.

Configures ho Apache interacts with PHP. This is not the same as the configuration for PHP itself; this is usually /etc/php.ini

This file also tells Apache that, if a directory in requested and the file index.php exists in that directory, then to return that file (Line 24).

Provides the configuration for how Apache interacts with Python.

If you are using squid as a reverse proxy, then this sets up an alias to a cgi script for squid that will provide usage statistics.

The file welcome.conf will display the Apache welcome if no default index page exists.

The file webalizer.conf sets up an alias for the usage data, and sets it so that this can only be read from localhost. Visit this page (from localhost) to see the usage statistics for your server.


Apache should have a separate user:group to run the server. (It does- apache:apache by default in CentOS). It does need to start as root so that it can bind to port 80. The choice is made in httpd.conf, lines 231-232. What would happen if this file is writable by other than root?

Permissions on the binaries need to be set correctly. What are the default permissions on the executable for the apache web server? [Indeed- what is the name of the executable?]

Permissions on the logs should be set so that only root can read them. What are the permissions on the directory /var/log/httpd? Why? These will store user supplied data- if they can get a process to read the data, it might be “trusted” as it comes from the local file system.

There is a separate file clobbering issuse described in http://localhost/manual/misc/security_tips.html#serverroot


NOTE- This is for non-SSL logging. Logs for SSL connections will be described later.

There are two kinds of logging- Request logging and Error logging.

Request logging
One must first create a log format using a LogFormat directive. See either http://localhost/manual/mod/mod_log_config.html#logformat or http://localhost/manual/mod/mod_log_config.html#formats for more details.

Four common log formats types are defined:

  • combined
  • common
  • referer
  • agent

By default, Apache uses the combined format. [See line 514.]

Logging itself can be accomplished with one of two commands:


(http://localhost/manual/mod/mod_log_config.html#customlog) or


(http://localhost/manual/mod/mod_log_config.html#transferlog). The second is rarely used.

Error Logging
Error logs are specified with the ErrorLog directive. [See line 472]. Read http://localhost/manual/mod/core.html#errorlog for details.

Error logs are written according to a priority specified by the LogLevel directive. Error levels are:

  • emerg Emergencies – system is unusable.
  • alert Action must be taken immediately.
  • crit Critical Conditions.
  • error Error conditions.
  • warn Warning conditions.
  • notice Normal but significant condition.
  • info Informational.
  • debug Debug level messages.

Error logs can be sent to

  • A file- e.g.

    ErrorLog /var/log/httpd/error_log

  • An application that will handle the data- e.g.

    ErrorLog “|/usr/local/bin/httpd_errors”

    Note that the programs so started are started by the web server, and may have root privileges.

  • To syslog, specifying a facility and priority- e.g.

    ErrorLog syslog:user

Try some of these different options.

Virtual Hosts

This is a way that a single web server can run multiple web sites.

  • You can have one host with multiple DNS names serve different websites depending on the hostname in the request
  • You can have one host with multiple IP addresses serve different websites depending on the IP address in the request.
  • You can have one host serve different websites depending on the port in the request.

These different web sites can have different

  • Server admin
  • Document root
  • Server Name

Log files
See http://localhost/manual/mod/core.html#virtualhost, http://localhost/manual/vhosts/, and http://localhost/manual/vhosts/examples.html for additional documentation.

What happens is the same directory is accessible to two or more virtual hosts? They both can access it! This can cause security issues, as we will shortly see.


The configuration for the SSL secured component of a website is contained in the file /etc/httpd/conf.d/ssl.conf

Line 12 loads the module needed for SSL

By default, SSL listens on port 443; this is enabled on line 443.

Lines 30-75 set options that are global to all SSL protected web sites on that server, including properties of the random number generators and the cache.

To configure a portion of the website to use SSL, Apache uses a <VirtualHost> directive, in lines 81-228. Note first that the directive <VirtualHost _default_:443> matches any IP address not listed in another <VirtualHost> directive, on port 443. [c.f. http://localhost/manual/mod/core.html#virtualhost%5D.

– Virtual hosts can specify their own document root separately from the main host; thus we can specify a different document root for the SSL portion of the web site. In the default configuration file, the DocumentRoot directive is commented out, and hence anything in the DocumentRoot for the main web site can also be served via SSL.

Recall, if a directory is accessible via two <VirtualHost> directives, then both directories will serve that document. Verify this behavior. Earlier you created a file for your web server to serve. Now access it via SSL (i.e. https://yoursite/yourfile). Ignore any SSL warnings for the moment, and verify that you get the same page.

Line 85 sets the server name for this virtual host. Remember that one apache server can use virtual hosts with different host names. See http://localhost/manual/mod/core.html#servername for more details.

Line 89 sets the location of the error log, line 90 sets the location of the transfer log and line 91 sets the log level for this virtual host.

Line 95 requires that SSL be used for access to this virtual host.

Remember- the virtual host directive here was <VirtualHost _default_:443>, so anything that comes in via port 443 to any IP adress not bound to another virtual host will use SSL. However- this does not mean that any access to a directory inside this virtual host will automatically require SSL. If a file is in the document root for more than one virtual host, then either host can serve that file! We have seen this already!

Don’t confuse the fact that the virtual host requires SSL with the notion that the files necessarily require SSL- that depends on the totality of your Apache configuration.

See http://localhost/manual/mod/mod_ssl.html#sslengine for the syntax

The directive SSLProtocol on line 100 specifies the versions of SSL that will be accepted. See http://localhost/manual/mod/mod_ssl.html#sslprotocol for the syntax.

Note that SSLv2 is known to be flawed; it is disabled by default in modern browsers (e.g. IE7+, FF2+)

The precise Cipher is set by the SSLCipherSuite directive in line 105.

The private and public key locations are set in lines 112 & 119.

Read the remainder of the configuration file; note the additional log statement in lines 224-225.

To illustrate, let us set up an SSL protected directory on our web server that is only accessible via SSL.

Create the directory /var/www/html/ssl. Be sure that permissions are set so that it can be read by user apache of group apache.

Create the file /var/www/html/ssl/index.html.

Verify that right now this file can be accessed via both ssl (https) and non-ssl (http).

Create the following Directory directives OUTSIDE THE (SSL) VIRTUAL HOST

<Directory "/var/www/html/ssl">
SSLOptions +StrictRequire

Why do these need to be outside the SSL virtual host? What is the best file to contain these? Why?

Restart Apache. Verify that your file can be accessed via SSL but not without SSL.

You should still be getting certificate warnings. If you have accepted the warnings from an earlier visit to your website, the warnings may no longer appear; simply close your browser and start again.

Now we are going to create our own certificates and set up our own CA to sign them; doing so will let us import the certificate of the CA into browsers so that all of the certificates signed by that CA will no longer raise browser warnings.

We will be using this host to act as the equivalent of a trusted signer like VeriSign or Thawte. This does not need to occur on the same machine as the web server; in fact it can be done on a machine that is completely isolated from the network.

Create the directory /root/certs. This directory will be used to hold the certificates for the CA.

These certificates are not the same as the certificates for the SSL websites that will later be signed. This directory must be maximally protected; if an outsider gains access to the certificates in this directory, they will be able to sign certificates just as you can- this would be bad. You probably want to set the permissions on that directory to 600 (or even to 000).

The common name (CN) of the CA needs to be different from the common name of any machine for which you generate a certificate. For simplicity, we will suppose that

  • The DNS name of the host is centos1.class
  • We will use the CN centos1_CA.class for the CA
  • We will use the CN centos.class for the certificates for the web server.

In the directory /root/certs run

# openssl genrsa -des3 -out ca.key 4096

This will generate the root key for the CA. Since this is the key for the CA, it should have a good passphrase.

Examine your CA key

# cat ca.key

Now we generate a certificate for our CA with our key. You will need the passphrase for your server key. You will need to enter some data for the CA certificate. Remember that the CN we will use for the CA is different than the name we will use for any web server certificates.

[root@centos1 certs]# openssl req -new -x509 -days 365 -key ca.key -out ca.crt
Enter pass phrase for ca.key:
You are about to be asked to enter information that will
be incorporated into your certificate request.
What you are about to enter is what is called a
Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [GB]:US
State or Province Name (full name) [Berkshire]:Maryland
Locality Name (eg, city) [Newbury]:Towson
Organization Name (eg, company) [My Company Ltd]:Towson University
Organizational Unit Name (eg, section) []:Security Laboratory
Common Name (eg, your name or your server's hostname) []: centos1_CA.class
Email Address []:professor@centos1.class

Now we create the directory structure for our keys and certificates for the SSL protected portion of our web site. The apache install has already created a key and certificate for the web server, located in /etc/pki/tls/. We will create a subdirectory in /etc/pki/tls/ just for our own purposes; this way we can keep all of these different certificates straight.

Create the directories /etc/pki/tls/certs/new/private and /etc/pki/tls/certs/new/certs. We will use the subdirectory private to store host keys while the subdirectory certs will hold- wait for it- certificates. Be sure to protect the private subdirectory- chmod 600.

Now we create a server key that will be used for the web site. Enter the private subdirectory and create a server key by running

[root@centos1 private]# openssl genrsa -out server.key 4096

You do not need a passphrase here; if you include one then you will need that passphrase whenever apache is started. Verify that you have a valid key

# cat server.key

If you want to see your public key, you can run

# openssl rsa -in server.key -pubout

Now we generate a certificate signing request (csr). Again you will need to answer some questions, but now about your server. The catch here is that the common name must match the name of your web site; otherwise your will see a domain mismatch error. Remember- this also must be different than the CN you selected for the CA.

[root@centos1 private]# openssl req -new -key server.key -out server.csr
You are about to be asked to enter information that will be
incorporated into your certificate request.
What you are about to enter is what is called a Distinguished
Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [GB]:US
State or Province Name (full name) [Berkshire]:Maryland
Locality Name (eg, city) [Newbury]:Towson
Organization Name (eg, company) [My Company Ltd]:Towson University
Organizational Unit Name (eg, section) []:Security Laboratory
Common Name (eg, your name or your server's hostname) []:centos1.class
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Now we ask the CA to sign our certificate; we will do this from the directory /etc/pki/tls/certs/new/certs

openssl x509 -req -days 365 -in /etc/pki/tls/certs/new/private/server.csr 
-CA /root/certs/ca.crt -CAkey /root/certs/ca.key -set_serial 01 
-out server.crt

Examine your certificate

cat server.crt

Now we wll tell the web server to use these keys. In the <VirtualHost> directive modify the following lines:

SSLCertificateFile /etc/pki/tls/certs/new/certs/server.crt
SSLCertificateKeyFile /etc/pki/tls/certs/new/private/server.key

Restart Apache. Check your logs (/var/log/messages and /var/logs/httpd/error_log) to be sure that Apache restarted cleanly. View the SSL enabled page in a browser; you should still see an error saying that the issuer certificate is unknown.

From the browser, view the certificates that are being used. You should see the certificate for the server, as well as the certificate of the CA.

Now we will import the key for the CA into our browser. Place the certificate ca.crt (NOT THE KEY) from the CA into a convenient location. In Firefox, navigate Edit -> Preferences -> Advanced -> View Certificates. Select Import, then select the file ca.crt; trust this CA to identify web sites. View the certificate you have just imported. Visit the web page- notice that all proceeds without error.

Notice that if you visit the web page without using the precise name in the certificate- by e.g. visiting https://ip/ssl rather than https://hostname/ssl then you will see that the certificate is only valid for the selected hostname.

Access Control

There are three important types of authentication

  • Basic Authentication
  • Digest Authentication
  • Form-based Authentication

The first two of these are part of the HTTP protocol (RFC 2167). The last is most common, and requires the web page(s) themselves to handle the authentication (via e.g. PHP). We will not cover this here.

Digest authentication, though an improvement on basic authentication, is not commonly supported by browsers; we will not cover this either.

Documentation on how to set up authentication can be found at http://localhost/manual/howto/auth.html

Here is a demonstration. For this purpose, we will put all of our configuration information in the main file (/etc/httpd/conf/httpd.conf) rather than in per-directory .htaccess files.

Create the directory /var/www/auth. We will store our authentication data here (outside of document root for the web server). Create the Apache password file, starting with a single user (BillPreston) as follows:

[root@centos1 auth]# cd /var/www/auth
[root@centos1 auth]# htpasswd -m -c /var/www/auth/passwd BillPreston
New password:
Re-type new password:
Adding password for user BillPreston

Note that the password for this user is manually entered.

Let’s view our password file:

[root@centos1 auth]# cat passwd

The -m option above told Apache to use the MD5 hash. Other options include DES (crypt()), SHA, and plaintext. More options for htpasswd can be found in the documentation at http://localhost/manual/programs/htpasswd.html

Let’s create a directory that will require password protection, and put a page inside.

[root@centos1 html]# mkdir /var/www/html/secret
[root@centos1 html]# cd /var/www/html/secret
[root@centos1 secret]# vi index.html
[root@centos1 secret]# cat index.html
This page is protected

At this point, we can still directly view the page at http://localhost/secret/. You should be able to explain why!

Now we update our configuration file (/etc/httpd/conf/httpd.conf) by adding the following:

<Directory "/var/www/html/secret">
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /var/www/auth/passwd
Require valid-user

Restart Apache. Check your logs to verify that the restart was clean.

Now we are required to authenticate with a valid user/password combination from our file before we can view this page. Verify this!

Full documentation (including how to set up groups) can be found at http://localhost/manual/howto/auth.html.

It is also possible to use other than text files for authentication, including LDAP and databases. Consult the documentation for further details.

Multiple IP Addresses

You may want to set up a host with multiple external IP addresses. These separate IP addresses can also have their own separate names. Since most services allow you to sepcify the IP address(es) on which the service listens, one physical host can appear to the network to be a range.

To set this up in, for example, CentOS, you can modify the network configuration scripts in /etc/sysconfig/network-scripts.

Create a new file, called ifcfg-eth0:0; copy it from your existing /etc/sysconfig/network-scripts/ifcfg-eth0. Modify the Device name in that file to read eth0:0. Modify the static IP address to whatever value you wish. You cannot use DHCP. You can delete the GATEWAY data. Do not modify the hardware address The resulting file will look something like the follwing:

[root@centos1 network-scripts]# cat ifcfg-eth0:0
# Advanced Micro Devices [AMD] 79c970 [PCnet32 LANCE]

Restart networking via /etc/init.d/networking restart You will be able to see the new interface in the GUI tools, like System -> Administration -> Network.

This process is called setting an alias for an interface. A similar process can be used on other linux dstributions.

  1. Bryan Krause
    January 14, 2012 at 11:51 pm

    Good Tutorial. Once slightly more advanced feature I feel should be pointed out about the way Apache handles its configuration system in general. I personally find it easier to manage a system when I can look in a single file for a particularity system website, or series of configurations. To accomplish this I will include a line at the end of my HTTPD.conf file with:
    “Include sites-enabled/*”
    This will set any files in this directory as an Apache configuration file. I then create a separate file in the same root directory with:
    “mkdir sites-avalible”
    Once this is created I will create all the configuration files in this directory, and symlink the files I want activated for my Apache configuration to sites-enabled. This give me the ability to quickly activate/deactivate any particular configurations quickly and effectively rather then look through one giant configuration file.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: