Apache + Blog
— print (last updated: Jul 13, 2009) print

Select font size:
Personalize this online document by providing values relevant to you.
  1. Replace the generic LOGIN by the actual login:
       
  2. Replace the generic MACHINE name by its actual name:
       
  3. Replace the generic TAZLOGIN by your actual taz login:
       
In this document we'll install Apache and configure it for a number of different common usages. Additionally, the common server-side language, Php, is installed. We will have the ingredients of the so-called LAMP (Linux/Apache/Php/MySQL) installation which offers a platform for Web Database applications and a wide variety of open-source web development tools.

As an application of LAMP, we'll install the WordPress blog which I would like for you to use to create development notes.

Apache Installation

This is a bit of overkill relative to what you need, but it helps make a point and may be useful later:
$ sudo apt-get install apache2 apache2-doc \
  php5 php5-cli php5-cgi php5-mysql
Key files and directories for Apache are these:
/etc/apache2/                   config files, modules, etc.
/etc/apache2/apache2.conf       main config file
/etc/apache2/httpd.conf         other (empty) config file
/etc/httpd/conf.d/*.conf        additional statup scripts
/etc/apache2/modules-*          available/enabled config files for modules
/etc/apache2/sites-*            available/enabled site definitions
/etc/init.d/apache2             control script
/usr/lib/apache2/               Apache modules
/var/www/                       Apache root
/var/log/apache2/               Apache Log files
The Apache Web services starts automatically. Test it by activating this URL in firefox:
http://localhost
Control the Apache server by
$ sudo /etc/init.d/apache2 [ status, start, stop, restart, reload ] 
The reload feature is generally preferred to restart because it does not actually stop the service and therefore is quicker when configuration files are modified. In certain cases, the stronger restart is necessary. Try this:
$ sudo /etc/init.d/apache2 reload 
In certain cases Apache may complain about lack of a host name (on a local system). If so, edit /etc/apache2/httpd.conf and add this line and try again:
ServerName localhost
If something goes wrong, the first place to look is usually this log file:
/var/log/apache2/error_log

Command-line http client

Sometimes it is useful to have a command-line http client, say for testing HTTP access remotely from a shell. The preferred choice is links, which you can install by doing:
$ sudo apt-get install links
Then try out the connection by typing:
$ links http://localhost

Php Installation

Key files and directories for Php are these:
/etc/php5/                      all config files
/etc/php5/apache2/php.ini       config file for Apache module
/etc/php5/cgi/php.ini           config file for CGI Php
/etc/php5/cli/php.ini           config file for command-line Php
/etc/php5/conf.d/               added config files (for both)
/usr/bin/php                    the command-line interpreter
/usr/lib/apache2/libphp5.so     the Apache Php module
/usr/lib/php5/200_____+lfs/     the Php plugin modules
Php, like Bash, is a script language, but it is a more complete programming language in itself which is intended to be executed on different platforms. It was written for, and is primarily dedicated to being a server-side scripting language for web programming.

The subdirectories apache2, cgi, cli of /etc/php5, each with its own config file, php.ini, indicate the three different ways in which Php can be used:
  1. as an Apache module: this is primarily what you're interested in
  2. as an executable for a CGI web program: this is the mode typically used in non-Apache web servers like IIS and Lighttpd.
  3. as a command-line program: The executable, /usr/bin/php, can serve as the basis for script programming.

Config file edit

Edit each of the three Php configuration files
/etc/php5/apache2/php.ini
/etc/php5/cgi/php.ini
/etc/php5/cli/php.ini
Look for the magic_quotes_gpc setting (gpc means for GET/POST/Cookie values)
magic_quotes_gpc = On
Change it to
magic_quotes_gpc = Off
After this modification reload the Apache server:
$ sudo /etc/init.d/apache2 reload
For the most part, only the "apache2" Php config file is relevant to our needs, but you might as well do all three.

User directories

User directories in Apache mean the association of a special directory in the user's home (by default, ~/public_html) with the given URL:
http://localhost/~LOGIN

Enable the userdir module (permitting user-based web)

Make the Apache configuration changes. In Ubuntu this involves having certain configuration files available in certain directories. To enable the userdir module do:
$ sudo a2enmod userdir
$ sudo /etc/init.d/apache2 reload
Alternatively, you could create the effect of a2enmod by hand with these commands:
# cd /etc/apache2/mods-enabled/
# ln -s ../mods-available/userdir.* .
# /etc/init.d/apache2 reload
In effect, enabling a module means to link it into the directory /etc/apache2/mods-enabled/ from the actual files is /etc/apache2/mods-available/. Verify the linking operation by doing:
$ ls -l /etc/apache2/mods-enabled
Ubuntu provides these software tools specific to its Apache configuration:
a2enmod          apache2 enable a module
a2dismod         apache2 disable a module   
a2ensite         apache2 enable a site
a2dissite        apache2 disable a site
The enablers simply link from the mods-available or sites-available directories to the mods-enabled or sites-enabled directories, respectively. The disablers remove these links. It is good to know exactly what happens by doing these operations because these "a2" operations do not occur in other Linux distributions.

Create the public_html directory

Create the public_html directory by doing:
$ mkdir ~/public_html
The only requirement for invoking an HTML file or Php script in ~/public_html is that it be readable ("r" permission) by the Apache web server which runs as the user (and group) of name "www-data". In order to read a file, the Apache web server must also be able to pass through ("x" permission) all directories in the path to this file.

Check the permissions on the path components by doing:
$ ls -ld  /  /home  ~  ~/public_html
drwxr-xr-x .. root  root   ... /
drwxr-xr-x .. root  root   ... /home
drwxr-xr-x .. LOGIN  LOGIN  ... /home/LOGIN
drwxr-xr-x .. LOGIN  LOGIN  ... /home/LOGIN/public_html
The permissions allow the Apache user (www-data) to pass through to public_html. In fact they are too permissive for a multiuser system where users have shell access. We discuss this issue below.

For some basic tests, create these two files: You should see the two files listed below; click to activate each one.
http://localhost/~LOGIN

Wordpress Blog

The wordpress website is:
http://www.wordpress.org/
You can download it in .zip or .tar.gz format. A recent version is this:
wordpress-2.7.1.tar.gz
Extract into your public_html directory. The .tar.gz version like this:
$ tar xzf wordpress-2.7.1.tar.gz -C ~/public_html
and the .zip version like this:
$ unzip wordpress-2.7.1.zip -d ~/public_html
creating the folder:
~/public_html/wordpress/
We'll see what needs to be done by trying to use it. Activate the wordpress URL:
http://localhost/~LOGIN/wordpress
Here we go:
  1. It says:
    There doesn't seem to be a wp-config.php file. I need this before we can get started...
    Click the Create a Configuration File button.
  2. It says:
    Sorry, I can't write to the directory. You'll have to either change the permissions on your WordPress directory or create your wp-config.php manually.
    OK, we'll change the permissions temporarily:
    $ ls -ld ~/public_html/wordpress/
    drwxr-xr-x ...
    $ chmod o+w ~/public_html/wordpress/
    $ ls -ld ~/public_html/wordpress/
    drwxr-xrwx ...
    
    Afterwards, do a browser refresh.
  3. Now it says:
    ... You will need to know the following items before proceeding.
    1. Database name
    2. Database username
    3. Database password
    4. Database host
    5. Table prefix (....)
    OK, we can do that. Let's use the preferred "wordpress" database, a user name "wp" and empty password
    $ mysql -u root
    mysql> create database wordpress;
    mysql> create user wp@localhost;
    mysql> grant all on wordpress.* to wp@localhost;
    mysql> quit
    
    Double check:
    $ mysql -u wp wordpress
    
    We're ready. Click Let's go!
  4. Database configuration. You only to change username to "wp" and the password to empty. Click Submit.
  5. It called me Sparky! I'm offended, but I'll swallow my pride and continue on. Click Run the install.
  6. It wants more:
    Blog title: MACHINE's blog    (or whatever)
    Email: whatever
    
    Click Install WordPress.
  7. Success. It tells me this:
    Username  	admin
    Password 	blah-blah-blah
    
    Note that password carefully! It is a random password that was generated just for you.
    Thanks alot! Another miserable password! I'll never remember that! Never fear, you probably never need to type this password per se. Put it in a file. Run this cat command, copy and paste it into the shell here, followed by Ctrl-D.
    $ cat > ~/wordpress-password
    blah-blah-blah
    Ctrl-D
    
    Finally, press Log In.
  8. The login screen. Login with Username admin. Type:
    $ cat ~/wordpress-password
    
    and copy/paste from the shell into the Password field.
  9. Click Add New on the left-hand side menu, and create your first blog entry. Click Publish on the right side. Click Log Out on the top right.
  10. Take a look again at:
  11. The world write permission is no longer needed. Everything is written to the database. So remove it:
    $ chmod o-w ~/public_html/wordpress/
    
  12. Make a root-level alias. Create the file /etc/apache2/conf.d/blog.conf with one line:
    Alias /blog /home/LOGIN/public_html/wordpress
    
    Reload Apache:
    /etc/init.d/apache2 reload
    
    Then test it it out:

Start Blogging!

Use it to detail anything that you discover outside the realm of the course content.

Tunnel Access to Apache

Choose a dedicated port, say 7080. We want to tunnel to port 80. You can run this from your Linux client machine, but the real test is from outside.

Start the tunnel

On a Linux client, run this shell command:
ssh -L 7080:MACHINE:80 TAZLOGIN@taz.cs.wcupa.edu
Again, for the Windows, use PuTTy.
  1. Select the "taz" line from the Saved sessions. Click the Load button.
  2. Go to Connection SSH Tunnels
  3. Enter 7080 in the Source port field
    Enter MACHINE:80 in the Destination field
  4. Click the Add button. It should create a line:
    L7080   MACHINE:80
    
  5. Go back to the Session and click Save. The tunnel is set up.
  6. Click Open and log in to taz.
As before, the only steps you need to do to "start the tunnel" are
  1. Start PuTTy
  2. Open the taz session and log in to taz

Test the tunnel

Test the tunnel's effectiveness by activating these URLs:
http://localhost:7080/~LOGIN
http://localhost:7080/blog

Special priviledges

The Apache configuration permissions granted to users via the userdir configuration file are limited. Take a look for yourself:
$ cat /etc/apache2/mods-enabled/userdir.conf
The Options and AllowOverride lines are what we need to expand upon for ourself, the administrator. To do so, create a file (as root):
/etc/apache2/conf.d/admin.conf
Make the contents this:
<Directory /home/LOGIN/public_html>
   Options All
   AllowOverride All
</Directory>

CGI execution

Apache, like any multi-purpose web server, has a myriad of ways to create HTML dynamically through server-side execution. Perhaps the oldest and simplest of ways to do so is to run an external program which generates the HTML code. The protocol by which the external program interacts with the web server is called CGI (Common Gateway Interface). Any programming language can serve toward this end, but script languages such as Perl usually favored over C/C++.

Apache requires several things for a program to be executed via CGI: We dealt with the Options issue by giving our public_html directory the options:
Options All
The All option includes ExecCGI. The other two issues require further configuration steps. Enable the loadable cgi module by doing:
$ sudo a2enmod cgi
Apache recognizes valid CGI scripts in several ways: being in a certain ScriptAlias directory, or having a certain file extension (using the AddHandler directive). We prefer the latter to allow a more general placement of CGI scripts. Edit
/etc/apache2/mods-enabled/mime.conf
Look for the commented line:
#AddHandler cgi-script .cgi
and uncomment it. Thus all files with the ".cgi" extension eligible for CGI execution. After these steps, reload Apache:
$ sudo /etc/init.d/apache2 reload

First Example

Create the file, ~/public_html/hello-bash.cgi:

hello-bash.cgi
#!/bin/bash # print the HTTP header echo content-type: text/html echo echo "<b>$(basename $0)</b>" on "<b>$HOSTNAME</b>," time: "<b>$(date)</b>"
The CGI script must be executable. Make it executable and execute it by hand.
$ cd ~/public_html
$ chmod +x hello-bash.cgi
$ ./hello-bash.cgi
If anything goes wrong, it will certainly not execute as a CGI script. Then refresh the browser for the directory listing:
http://localhost/~LOGIN
and execute by clicking the hello-bash.cgi link. Unlike shell behavior, the shebang line
#!/bin/bash
is required for CGI execution. Additionally, the HTTP protocol requires that the content sent to a browser start with an HTTP header consisting of one or more lines which tell to the browser what is coming. The header is separated from the content by a single empty line (the echo statement by itself).

The simplest header consists the one line:
content-type: text/html
The header must be separated from the content by an extra newline — this explains the need for the empty echo statement.

In general, Bash is not a good choice for CGI programming due to its strictly interpreted nature and limited inherent functionality. It it is used here for demonstration purposes only.

Suexec mode

Apache CGI execution can be made to run in what is referred to as suexec (switch user execution) mode. This means that Apache, when executing a CGI program, switches from the Apache user (www-data in Ubuntu) to the CGI program's owner and runs with the owner's permissions. This feature allows users to create CGI scripts can write to auxiliary files owned by the user.

Install and enable the relevant Apache module and reload:
$ sudo apt-get install apache2-suexec
$ sudo a2enmod suexec
$ sudo /etc/init.d/apache2 reload

File permissions

To be permitted to run in suexec mode neither the CGI program nor the directory in which the program resides may have group or world write (w) permission. The script itself need have no "group" nor "other" permissions whatsoever. Therefore, for added security, we can do this for all CGI scripts:
$ chmod 700 hello-bash.cgi
Look at long listing (ll) on this file. Then double-check that hello-bash.cgi still executes in the browser.

A hit counter script

Create the following script counter-bash.cgi below in ~/public_html:

counter-bash.cgi
#!/bin/bash hits_file=_HITS_ # print the HTTP header plus an HTML header echo content-type: text/html echo echo '<h2>Hit Counter</h2>' hits=$(cat $hits_file) # initially empty ((++hits)) # empty acting like 0 echo -n $hits > $hits_file echo number of hits: $hits
Make it executable
$ chmod 700 counter-bash.cgi
Refresh the directory listing in the browser to pick it up and run it. The script simply records and counts the "hits", or accesses to this script. Press the refresh button on the browser several times to see the effect.

The significance of this script is that it writes to the file _HITS_ in your ~/public_html directory. Apache's suexec modules permits such behavior because the script runs with the permission of its owner — you.

Discussion

Home directory security on multiuser systems

On multiuser systems where home-directory security is an issue, the default permissions allows access to your home directories by other users. There are a number of ways to close this security hole. The idea is to allow, other than you, only the www-data user access to your home directory. This can done as follows:
$ chmod 710 ~
$ sudo chgrp www-data ~
$ ls -ld ~                      (see what happened)
Double-check that your URL still works:
http://localhost/~LOGIN
Unfortunately, this protection can easily be subverted, either intententionally or not, because the user can easily use chmod to reset the permissions. Even worse, the normal user does not have the ability to change the group ownership to www-data. but could change it to the original (same as user name) and thereby make his/her personal website unusable unless the permissions are opened up.

Error logs and CGI errors

Whenever an error happens using HTTP and you can't immediately discern the cause of the problem, look in one of files where Apache errors are reported:
/etc/apache2/logs/error_log
/etc/apache2/logs/suexec.log
Usually you would want to use the "tail" or "tail -f" commands. You must be root or belong to the adm group to read these files.

Test group-writeability failure

It may seem odd that group-writeability should be a problem since the group is effectively the owner, but Apache's suexec is made this way because group access is not always as restrictive as owner access. Below are two tests of which illustrate the group-writeability failure for suexec. Open a dedicated shell and run this command to display the errors:
$ tail -f /var/log/apache2/suexec.log
  1. As a first test, add group-write permission to hello-bash.cgi:
    $ cd ~/public_html
    $ chmod g+w hello-bash.cgi
    $ ll hello-bash.cgi
    
    Then, from the browser, run this, and observe the output in the shell: Then fix the error by
    $ chmod g-w hello-bash.cgi
    
    and verify in the browser that the script is OK again.
  2. As a second test, make the directory containing the script group-writeable:
    $ cd ~/public_html
    $ chmod g+w .
    
    Try running the script again and observing the error in the log file. After the test, fix the problem
    $ chmod g-w .
    

Root CGI Scripts

Apache's default root directory in an Ubuntu system is /var/www. This feature is specified by the DocumentRoot variable defined in the file
/etc/apache2/sites-available/default.conf
and corresponds to the URL:
http://localhost
Apache CGI sets up support for any program placed in the directory /usr/lib/cgi-bin (regardless of its extension). A CGI script in this directory will correspond to the URL:
http://localhost/cgi-bin/<script name>
For security reasons, Apache will not execute a CGI file owned by root since this, via the suexec mechanism, would give the file read/write capabilities on root-owned files with countless potential security holes. CGI scripts run in Apache's root are usually owned by the Apache user, www-data.

Copy hello-bash.cgi into this script directory:
$ sudo cp ~/public_html/hello-bash.cgi /usr/lib/cgi-bin/
and then test the URL:
http://localhost/cgi-bin/hello-bash.cgi
It fails because root owns the script. Fix it:
$ sudo chown www-data /usr/lib/cgi-bin/hello-bash.cgi
then test the URL:
http://localhost/cgi-bin/hello-bash.cgi
Finally, give a different extension to prove it doesn't matter in this directory:
$ cd /usr/lib/cgi-bin/
$ sudo cp -a hello-bash.cgi hello-bash.sh
then test the URL:
http://localhost/cgi-bin/hello-bash.sh


© Robert M. Kline