Suexec

suEXEC allows Apache to run CGI programs as a different user than that of the Apache process. suEXEC significantly reduces many of the security risks associated with running CGIs. suEXEC is enabled for all DreamHost users and cannot be disabled. suEXEC performs checks on the executed CGI to ensure security for the server. It has strict permission checking that will result in a "500 Internal Server Error" if the permissions of the script are not setup correctly, and it cleans the environment by only passing through those environment variables considered safe.

Script Permissions
Because of the way suEXEC handles security, the directory in which your CGI script lives and the script itself must not be writable by anyone but the user. If it is writable, you will receive a "500 Internal Server Error". The script must also be executable. The easiest way to set permissions is with :

$ chmod 755 script.cgi

Apache Module mod_env
Because suEXEC cleans the environment by wiping out all the environment variables except those deemed safe by the server's configuration, the directives provided by mod_env such as,  , and   will not work as expected. Some third-party applications use environment variables for directory-specific configuration. For example, Movable Type allows you to host multiple instances of it from a single source base. You supply the path to an instance-specific configuration file via the environment variable.

Say you have foobar.cgi

use strict; use cgi; $ENV{FOOBAR} ||= 'default'; my $q = CGI->new; print $q->header; print $ENV{FOOBAR};
 * 1) !/usr/bin/perl

installed at both /home/username/yourdomain.com and /home/username/yourotherdomain.com. In your first domain's directory, you drop an .htaccess with the directive

SetEnv FOOBAR foo

and

SetEnv FOOBAR bar

into your second domain's directory. When you visit yourdomain.com/foobar.cgi in your browser, you'd expect it to print, and when you visit yourotherdomain.com/foobar.cgi, you'd expect. Instead,  would be printed both times.

At first, you might assume mod_env is not installed or that the  directive is not allowed from .htaccess. In fact,  is working just fine. It is setting the environment variable; suEXEC just isn't passing it to your CGI script. On the one hand, if you're developing your own application, you can just keep this in mind while developing it and not design your application to use non-standard environment variables. If, on the other hand, you are using a third-party application and modifying the source code would be prohibitively difficult and/or time-consuming (or if you just gotta have those custom environment variables in the application you're developing yourself), there are a few workarounds.

Workaround A: Prepend HTTP_ to Variable Name
The way DreamHost has suEXEC configured, it allows any environment variable that begins with  through. So, if you change your .htaccess to  and use   in your CGI script, it will work as expected.

This workaround is probably best suited to applications you're developing yourself. Digging through the source code of third-party applications (especially large applications, which may have hundreds of thousands of lines) and changing each instance of  to   would be both prohibitively complex and time-consuming, not to mention you'd have to redo all that work every time you upgraded the application. This solution is a bit hacky, but it works.

Workaround B: Edit the CGI Script to Set the Variable Itself
You can place  at the top of your script. Like Workaround A, this workaround would be best suited to applications you're developing yourself. Its usefulness would be limited even then though. The purpose of using environment variables is to alter the behavior of your script based on the context (or environment) its executed from. If you set the variable from within the script itself, the behavior of the script will be the same regardless of the context its executed from.

Workaround C: Create a Wrapper Script
Create wrapper.cgi.

export FOOBAR=foo exec /home/username/yourdomain.com$SCRIPT_URL
 * 1) !/bin/sh

If you just have one CGI script you want to set an environment variable for, you can change the last line of the wrapper to. If you need to set an environment variable for dozens or even hundreds of files of a third-party application (such as Movable Type),  allows you to determine which script was requested and set the environment variable for that script.

Then use .htaccess to redirect requests for the script to wrapper.cgi.

RewriteEngine On RewriteRule ^application/.*\.cgi /wrapper.cgi


 * application is the directory where your (third-party or in-house developed) app lives.
 * If you're only setting an environment variable for one (or a few) CGI scripts, you can specify the script in the  (e.g.  ). Just add additional  s for additional scripts.
 * As you can imagine, just continuing to add s past a few scripts would become unwieldy. Then it would be best to match all files ending with a specific file extension. By matching only files ending with .cgi, .pl, .py, .rb, etc., static files such as HTML documents and images are unaffected.
 * If your wrapper script is in the same directory as the scripts you want wrapped and you're matching by pattern (this doesn't matter if your matching a specific file name), your wrapper must have a different file extension than your scripts. For example, if your wrapper ends in .cgi, you might want to use .pl or .py  for your scripts.
 * wrapper.cgi can call a script outside your domain's directory. This is actually what you probably want to do. That way the wrapper in both /home/username/yourdomain.com and /home/username/yourotherdomain.com can refer to the same script(s) in /home/shared.

Workaround C is a kludge but is suitable for a far wider range of cases than either Workaround A or Workaround B. Unlike Workaround A, you can set an environmental variable for hundreds (or thousands!) of files by editing just two files (wrapper.cgi and .htaccess). And if setting an environmental variable for a third-party application, you don't have to modify any files when you upgrade the application. You can have multiple wrapper scripts, so unlike Workaround B, the context (or environment) can actually alter the behavior of the script(s). Just copy wrapper.cgi and .htaccess from yourdomain.com to yourotherdomain.com, edit wrapper.cgi and change  to , and voilà!