Edgewall Software

Trac on Red Hat Enterprise Linux 5

Installing Trac software and dependencies

Installing Trac on Red Hat Enterprise Linux 5 is relatively easy thanks to RPMforge packages from Dag and Dries. Visit http://dag.wieers.com/rpm/FAQ.php#B for details on how to configure your server to be able to access RPMforge.

Once you have your server configured to use the RPMforge package repository, installing Trac is accomplished by running:

yum install trac

Once the software is installed, you will need to configure it as documented below to get it up and going.

Configuration overview

This guide will result in the following configuration:

  • HTTP requests will be handled by Apache HTTP Server ("Apache"):
  • Trac will be run within its own separate and limited user account:
    • No Trac code will be executed inside Apache processes;
    • Trac data will be stored within a SQLite database;
    • All data files are owned/readable/writable only by the dedicated Trac user account;
  • HTTP requests will be proxied from Apache to Trac via mod_proxy_ajp.

The rationale for this configuration is:

  • We can take advantage of Apache's features such as SSL, and advanced authentication (eg LDAP);
  • No extra code or modules that could effect the security or stability of the Apache server are introduced;
  • Individual instances of Trac are isolated and can have their resource usage easily measured;
  • Multiple versions of Trac could be run if so desired.

If you are dedicating an entire machine to Trac and don't require such high levels of isolation, you may wish to simply embed Trac in Apache. See TracOnRHEL for details. It is a much simpler procedure.

You may also want to simply just run the trac standalone daemon on a high port.

It is assumed that Subversion is already installed/configured and in a working state.

In the examples below, the end goal will to have a trac environment setup for PROJECT_NAME available at:

https:trac.example.org/PROJECT_PATH

Creating the dedicated Trac account

Create a user account for Trac:

$ su -
# useradd -d /home/trac -c 'Trac server user' trac

Be sure to add the trac user to any groups necessary for access to your subversion repository. You may also need to add it to the group that owns the Apache password file so that it can authenticate users.

Create a new project environment

# su - trac
$ mkdir -p -m 0700 $HOME/projects
$ trac-admin $HOME/projects/PROJECT_NAME initenv

See TracInstall for generic information.

Web server gateway

In order to connect Apache to Trac we will make use of http://trac.saddi.com/flup which is an AJP to WSGI gateway. Download the latest prepackaged tarball version of flup into the trac account and install:

$ tar zxf flup-0.5.tar.gz
$ cd flup-0.5
$ mkdir -p -m 0700 $HOME/lib/python
$ PYTHONPATH=$HOME/lib/python python setup.py install --home=$HOME

Now we need to create a simple gateway:

$ mkdir -m 0700 $HOME/bin

then create the file $HOME/bin/ajp_to_wsgi_gateway with the following contents:

#! /usr/bin/python
#
#
# AJP to WSGI gateway to run Trac.

import os, sys

# System path configuration. Nasty hack below.
sys.path.append(os.environ['HOME'] + '/lib/python/setuptools-0.6c3-py2.4.egg')
sys.path.append(os.environ['HOME'] + '/lib/python/flup-0.5-py2.4.egg')

def usage() :
        print """Usage: ajp_to_wsgi_gateway PATH_TO_TRAC_ENV URL_PREFIX PORT"""
        sys.exit(1)

if __name__ == '__main__':

        if len(sys.argv) != 4 :
                usage()
        else :
                path = sys.argv[1]
                prefix = sys.argv[2]
                port = int(sys.argv[3])

        # WSGI application configuration.
        os.environ['TRAC_ENV'] = path
        os.environ['PYTHON_EGG_CACHE'] = path + '/eggs'

        import trac.web.main
        application = trac.web.main.dispatch_request

        # AJP to WSGI gateway.
        import logging
        from flup.server.ajp import WSGIServer
        ret = WSGIServer(application,
                         bindAddress=('localhost', port),
                         scriptName=prefix,
                         loggingLevel=logging.ERROR,
                         debug=False
                        ).run()
        sys.exit(ret and 42 or 0)

You may need to modify the script above to fixup the system path information. Set the permissions on the script:

chmod 700 $HOME/bin/ajp_to_wsgi_gateway

Create $HOME/bin/trac_server_wrapper with the following contents:

#! /bin/bash
#
# Wrapper script to start a trac server for multiple environments.

export PYTHONPATH=$HOME/lib/python

trac_project()
{
        local trac_env=$1
        local path_prefix=$2
        local port=$3
        local status=42

        while test $status -eq 42; do
                $HOME/bin/ajp_to_wsgi_gateway "$trac_env" "$path_prefix" $port
                status=$?
        done &
}

# Individul project servers.
trac_project $HOME/projects/PROJECT_NAME /PROJECT_PATH SERVER_PORT

Edit the script to replace PROJECT_NAME, PROJECT_PATH, and SERVER_PORT as appropriate. PROJECT_PATH must not have a '/' after it and does not include the protocol or hostname.

Set the permissions on the script:

chmod 700 $HOME/bin/trac_server_wrapper

Set the server script to start on system boot:

$ cat <<EOF > cron.fragment
@reboot $HOME/bin/trac_server_wrapper
EOF
$ crontab cron.fragment
$ rm cron.fragment

Now start the gateway:

trac_server_wrapper

Alternative web server interface

At the time of writing, the above scripts appear to have problems with escape sequences in URLs. For example, this will mean you can't put spaces in milestone names, and you won't be able to browse source files whose names contain spaces. There is however an alternative way of presenting an AJP interface to Apache which can be configured to avoid this problem, and yet retain the advantages of running Trac in its own user account.

The way to do this is to run tracd with --protocol=ajp and the --unquote switch that was added in trac 0.11.4 (if you're running an earlier version, refer to this patch). For example:

tracd --auth="*",/var/www/passwords/passwd,MyRealm --port=SERVER_PORT
  --hostname=localhost --protocol=ajp --unquote --env-parent-dir=$HOME/projects
  --base-path=/PROJECT_PATH --daemonize --pidfile=$HOME/trac.pid --umask=63

but all one line. It's probably easiest to put this in a shell script somewhere. You'll need to add this to the trac user's crontab to be executed at each reboot.

Common web content

Now we copy the common icons, stylesheets, etc that Apache will server directly into our hosting account:

$ mkdir -m 0701 $HOME/public_html
$ cp -a /usr/share/trac/htdocs/* $HOME/public_html/trac
$ chmod 701 $HOME

Edit $HOME/projects/PROJECT_NAME/conf/trac.ini and adust the following values:

  • In the [header_logo] section set src to /trac/trac_banner.png
  • In the [project] section set icon to /trac/trac.ico
  • In the [trac] section set htdocs_location to https:trac.example.org/trac

Start trac servers

Start trac by running:

$ trac_server_wrapper

SELinux configuration

Apache will need network access in order to communicate to the trac daemon. As root run:

# setsebool httpd_can_network_connect on

For Apache to be able to access the common trac files, the will need to be correctly labeled. As root run:

# fixfiles restore /home/trac

Apache configuration

Create your SSL certificate for trac.example.org. As root:

# cd /etc/pki/tls/certs
# make trac.example.org.crt

Make sure the mod_ssl' package is installed.

Create an Apache virtual host in /etc/httpd/conf/httpd.conf (or an included file) with contents like:

<VirtualHost YOUR_IP_ADDRESS:443>
        ServerName trac.example.org:443

        ServerAdmin support@example.org
        DocumentRoot /home/trac/public_html

        CustomLog logs/trac.example.org_log combined
        ErrorLog logs/trac_error_log

        <IfModule mod_ssl.c>
        SSLEngine on

        SSLCertificateFile /etc/pki/tls/certs/trac.example.org.crt
        SSLCertificateKeyFile /etc/pki/tls/private/trac.example.org_key
        #SSLCACertificateFile /etc/pki/tls/certs/A_CA_CERT.crt
        </IfModule>

        # Security restrictions.
        <Location />
                # Require password authentication via LDAP.
                #AuthType basic
                #AuthName "Trac"
                #AuthBasicProvider ldap
                #AuthLDAPURL ldap://localhost/dc=example,dc=org
                #AuthLDAPGroupAttribute memberUID
                #AuthLDAPGroupAttributeIsDN off
                #require ldap-group cn=devel,ou=Groups,dc=example,dc=org

                #Order Allow,Deny
                #Allow from staff.example.org
        </Location>

        # Trac runs as a daemon inside the 'trac' account.
        # It is written in Python, however there is a
        # AJP <-> WSGI gateway that handles the requests on
        # a per project basis.
        Redirect         /PROJECT_PATH      https://trac.example.org/PROJECT_PATH/
        ProxyPass        /PROJECT_PATH/     ajp://localhost:SERVER_PORT/PROJECT_PATH/
        ProxyPassReverse /PROJECT_PATH/     ajp://localhost:SERVER_PORT/PROJECT_PATH/
</VirtualHost>

Check the syntax via service httpd configtest and restart via service httpd restart.

Everything should now work!

Troubleshooting

The above is quite complicated and easy to make a mistake with. Things to check:

  • Check the apache server error log and the trac user error log;
  • Check with ps xfwww that ajp_to_wsgi_gateway is running;
  • Check with netstat -tunlp that the gateway is listening on the correct port;
  • Modify ajp_to_wsgi_gateway and set debug to True and loggingLevel to logging.DEBUG to see the requests hit the gateway;
  • Modify $HOME/projects/PROJECT_NAME/conf/trac.ini and set log_type to stderr to get error messages from trac itself.
Last modified 16 years ago Last modified on Apr 2, 2009, 4:09:23 PM
Note: See TracWiki for help on using the wiki.