Trac and Apache suEXEC
Trac in CGI-mode doesn't play very well with Apache suEXEC. The suEXEC feature provides users of the Apache HTTP Server the ability to run CGI and SSI programs under user IDs different from the user ID of the calling web server. Normally, when a CGI or SSI program executes, it runs as the same user who is running the web server.
Setting the TRAC_ENV
environment variable as described in TracInstall will not work when using suEXEC feature, because the environment variables are filtered and only a limited subset reaches the CGI program.
There are obvious workarounds to make things work:
- Recompile suexec to let it pass the
TRAC_ENV
variable; this requires root permissions and therefore not advisable. - Change our
trac.cgi
script to set theTRAC_ENV
variable by itself, to do this we edittrac.cgi
file and add to the start of the script:import os os.environ['TRAC_ENV'] = '/path/to/projectenv'
- Make a wrapper script:
#!/bin/bash export TRAC_ENV='/path/to/projectenv' exec /path/to/trac/trac.cgi
Note: This is a kludge, but works.
Multiple Projects under suEXEC
When hosting multiple projects under suEXEC, you can either copy the CGI script and change the TRAC_ENV
setting for each script, or make a wrapper script around it. Here is a script to work around the stripping of environment variables done by suEXEC:
#!/bin/bash user="marcenuc" prj="${PATH_INFO#/}" prj="${prj%%/*}" export TRAC_ENV="/home/${user}/.trac/prj/${prj}" export SCRIPT_NAME="/~${user}/prj/${prj}" export PATH_INFO="${PATH_INFO#/${prj}}" export PYTHONPATH="/home/${user}/sw/lib/python2.3/site-packages" exec ./trac.cgi
Multiple Projects under Plesk/suEXEC/same domain
Added by torgny at sbbs.se
The above script works well if you want to have a Trac instance for each user, but it doesn't really help if you have several projects under the same site, SourceForge style. In order to solve this under Linux Red Hat with Plesk, I did the following:
First, from the Apache configuration (vhost.conf
in this case), replace DOMAIN
with the domain you are adding:
RewriteEngine on RewriteRule ^/projects/+$ /projects/index.php [L] RewriteCond /home/httpd/vhosts/DOMAIN/private/tracs/$1 -d RewriteRule ^/projects/([^/]+)(/?.*) /projects/wrap.cgi$2 [S=1,E=TRAC_ENV:/home/httpd/vhosts/DOMAIN/private/tracs/$1] RewriteRule ^/projects/(.*) /projects/index.php Alias /trac/ /usr/share/trac/htdocs/ <Directory "/usr/share/trac/htdocs"> Options Indexes MultiViews AllowOverride None Order allow,deny Allow from all </Directory> <Directory "/home/httpd/vhosts/DOMAIN/httpdocs/projects"> AllowOverride None Options ExecCGI -MultiViews +SymLinksIfOwnerMatch AddHandler cgi-script .cgi Order allow,deny Allow from all </Directory> <LocationMatch "/projects/[[:alnum:]]+/login"> AuthType Basic AuthName "Trac" AuthUserFile /home/httpd/vhosts/DOMAIN/private/.htpasswd_trac Require valid-user </LocationMatch>
Now add the folder ~/httpdocs/projects
.
In that folder, either symlink trac.cgi
or place a copy, and add index.php
. index.php
acts as the default page when a project without an existing Trac environment is requested.
Now, for the wrap.cgi
bash script:
#!/bin/bash DOMAIN="trac.edgewall.com" project="${SCRIPT_NAME#/projects/}" export TRAC_ENV="/home/httpd/vhosts/${DOMAIN}/private/tracs/${project}" export SCRIPT_NAME="/projects/${project}" export PATH_INFO="${PATH_INFO#/${SCRIPT_NAME}}" exec ./trac.cgi
The script above does all the work-around magic to make sure everything works between suEXEC and Trac in CGI mode. It also gives you multiple projects support.
Multiple Projects, suExec, and RHEL 4
Added by mjs at clemson.edu
Here are some points specific to a RHEL installation.
My layout is as follows:
- Project Trac installations are in
/home/tracker/Trac/Projects/project-a
,/home/tracker/Trac/Projects/project-b
, etc. - The Trac site is a separate vhost from our other Web pages.
- The Trac site lives in
/home/tracker/Trac/htdocs/
. /home/tracker/Trac/cgi-bin
is a symlink to/var/www/cgi-bin/tracker/
(see below).- URLs are
http://trac.example.com/projects/project-a
, etc.
Red Hat compiles suExec so that it only executes CGI scripts that live below /var/www
. You cannot symlink individual scripts, but you can symlink a directory. This means that we can't drop CGI scripts under doc root. The scripts will have to live in the cgi-bin
subdirectory. Scripts must also not be group-writable.
The Trac vhost is defined as follows:
<VirtualHost *:80> ServerAdmin webmaster@example.com DocumentRoot /home/tracker/Trac/htdocs ServerName trac.example.com RewriteEngine on RewriteRule ^/projects/+$ /projects/index.html [L] RewriteCond /home/tracker/Trac/Projects/$1 -d RewriteRule ^/projects/([^/]+)(/?.*) /cgi-bin/tracwrap.cgi$2 [S=1,PT] RewriteRule ^/projects/(.*) /projects/index.html ScriptAlias /cgi-bin/ "/home/tracker/Trac/cgi-bin/" SuexecUserGroup tracker tracker ErrorLog /var/log/trac/error_log CustomLog /var/log/trac/access_log combined Alias /icons /home/tracker/Trac/htdocs/icons </VirtualHost>
Notes:
- The ScriptAlias line enables CGI script invocation in the named subdirectory. This subdirectory must be a symlink to a directory under
/var/www/cgi-bin
. - The second RewriteRule finds the project name and appends anything following it to the rewritten URL. Normally, the result of a RewriteRule is appended to the path to doc root. The PT ("Pass Through") flag prevents this, so
/cgi-bin/tracwrap.cgi
is invoked as a script. - The E flag in torgny's example is superfluous, as suExec strips it from the environment anyway.
As above, the tracwrap.cgi
script sets environment variables for trac.cgi
depending on the project name:
#!/bin/bash proj="${SCRIPT_URL#/projects/}" project="${proj%${PATH_INFO}}" export TRAC_ENV="/home/tracker/Trac/Projects/${project}" export SCRIPT_NAME="/projects/${project}" exec ./trac.cgi
I found that the variables you need to manipulate are quite different than in torgny's example. SCRIPT_URL
contains the entire local URL, e.g., "/projects/project-a/login"
and PATH_INFO
already contains anything after the project name. So to get the project name, you need to strip "/project/"
off the front of ${SCRIPT_URL}
and "${PATH_INFO}"
off the end. On entry, SCRIPT_NAME
contains "tracwrap.cgi"
, not anything related to the project name.
See also: TracInstall, TracMultipleProjects