Common Problems with Perl/CGI Scripts

This document is designed to discuss some of the common problems which prevent Perl/CGI (Common Gateway Interface) scripts from functioning properly. It was compiled from numerous web pages and personal experience. Many of the problems with Perl/CGI execution are specific to the server operating system and configuration. As a result, you should consult with the system administrator. This example is specific to a Red Hat Linux 7.x installation with the Apache web server with suEXEC enabled.

Where is Perl?
For some reason, Perl is installed in different locations. The most common location is /usr/bin/perl but there are many other possibilities. Often, a given Linux distribution will provide symbolic links from this location to the "real" location of the Perl interpreter. If this is not the case for your server, use the following to find perl:

whereis perl

If Perl is installed, the first entry in the list will be the location of the interpreter. Other entries may include the compressed documentation in the form of man pages

perl: /usr/bin/perl /usr/share/man/man1/perl.1.gz

This first entry should be used for the sha-bang line in each program:


Does the program work?
Before attempting to run a program as a CGI, you should try to run it from the command line. Log in via ssh (Secure Shell), change to the directory where the script resides and try one of the following:



perl scriptname

These will attempt to run your program. If you receive errors, try the following diagnostics:

perl -c scriptname

This will check the syntax of the Perl script and ensure that you have not mistyped function names or have mismatched quotation marks, parentheses, braces, or brackets. In the later cases, sometimes the line number reported in the error message is after the last line in the program. If so, you are probably missing a curly brace.

If you get in the habit of entering both the opening and closing curly braces at the same time and indented at the same level, this will minimize problems of this type. Although not used in many computer books, the following style has served me well:

  if ($a > $b)
    # Code to execute if true
    # Code to execute if false
When typing the above, enter both the opening and closing curly braces on separate lines and then go up to insert the code between them.

There are other ways to help ensure that your program will work. One is to use the -w option when launching perl either at the command line or as part of the sha-bang line.

If the warnings are confusing, add this line to your program:

use diagnostics to get more verbose error messages with human-readable explanations.

Once you are testing your script for CGI functionality, you may find useful information in the Apache web server logfiles. On our server the two of interest are: /var/log/httpd/access_log and /var/log/httpd/error_log and /var/log/httpd/suexec_log which contain information about system accesses via the web server. If present, the suexec_log will usually provide the reason why an Error 500--Internal Server Error is generated but only if you read it carefully. The logfiles are normally viewed using the tail command:

tail /var/log/httpd/suexec_log

Will the script communicate via CGI?
CGI (Common Gateway Interface) is a set of rules and procedures for communication between web browsers and scripts on web servers. Almost any programming language could be used to create CGI scripts, including C and even Bash shell scripts. Perl is the most common, however.

To run properly, the first two lines of the output must be Content-type: text/plain or Content-type: text/html followed by a blank line. If either of these is not present, the program will not work as a CGI script. The most common way to achieve this is:

print "Content-type: text/plain\n\n";

Capitalization and spelling are very important. One way to test this from the command line is:

perl scriptname | head -n2

This will execute your program and send the first two lines of its output to the terminal screen. You should see the "Content-type" line followed by a blank line.

Does the program have the correct line endings?
Perl is especially sensitive to line endings. Different operating systems use different ways to indicate when a line in a textfile has ended.

SystemLine Ending
MacOS 9\r
MacOS X\n

Perl will "choke" if the line endings are not the Unix/Linux style (\n). Fortunately, there are utilities to convert the line endings. The easiest program to use is called dos2unix and it can convert either Macintosh or DOS/Windows line endings to Unix/Linux line endings:

dos2unix scriptname

Are the permissions correct?
When executing a script from the command line (via perl scriptname) we can get away with not setting the file to be executable. However, when we use CGI, the script must have permissions which are appropriate.

A Perl CGI script must be executable and must be executable by the web server. In a default Red Hat Linux 7.x server where the Apache web server software is installed from RPM (Red Hat Package Manager) files, the user 'apache' on the system is used to run Perl CGI programs. As such, the user 'apache' must have permission to execute the program.

When we display a long directory listing (ls -l), there are indications of the permissions granted for the owner of the file, members of the group associated with the file, and every other user on the system.

There are three types of access permission for each type of user: Read, Write, and Execute. We can assign binary-weighted numbers to each of these: R=4, W=2, X=1. When we want to turn on a given permission, we add this weighted number. Repeat the process for each user type. For example permissions of rwxr-x--- are expressed numerically as 750.

The correct permission setting for most Perl scripts is 755. We can set these using

chmod 755 scriptname

Once this is done, it should be possible to use the ./scriptname method to run the program from within the directory where the program exists. The program output should go to the terminal screen.

IMPORTANT: The program must not be writable by "other" users on the system. As a result, when suExec is active, permissions of 777 will not work.

Is the ownership correct?
To further complicate matters, the script has to be in a certain kind of directory and have the right kind of ownership.

The program has to be in a specially-prepared directory which is known to the Apache web server and which has the correct permissions and ownership.

The Apache web server in the Red Hat Linux 7.x distribution comes with suExec turned on. The only way to turn this off would be to recompile Apache from source code. suExec is a "wrapper" which launches your Perl script if, and only if, certain conditions are met. Below is a table with these conditions and rationales for them from the Apache documentation ( website:

Was the wrapper called with the proper number of arguments? The wrapper will only execute if it is given the proper number of arguments. The proper argument format is known to the Apache web server. If the wrapper is not receiving the proper number of arguments, it is either being hacked, or there is something wrong with the suEXEC portion of your Apache binary.
Is the user executing this wrapper a valid user of this system? This is to ensure that the user executing the wrapper is truly a user of the system.
Is this valid user allowed to run the wrapper? Is this user the user allowed to run this wrapper? Only one user (the Apache user) is allowed to execute this program.
Does the target program have an unsafe hierarchical reference? Does the target program contain a leading '/' or have a '..' backreference? These are not allowed; the target program must reside within the Apache webspace.
Is the target user name valid? Does the target user exist?
Is the target group name valid? Does the target group exist?
Is the target user NOT superuser? Presently, suEXEC does not allow 'root' to execute CGI/SSI programs.
Is the target userid ABOVE the minimum ID number? The minimum user ID number is specified during configuration. This allows you to set the lowest possible userid that will be allowed to execute CGI/SSI programs. This is useful to block out "system" accounts.
Is the target group NOT the superuser group? Presently, suEXEC does not allow the 'root' group to execute CGI/SSI programs.
Is the target groupid ABOVE the minimum ID number? The minimum group ID number is specified during configuration. This allows you to set the lowest possible groupid that will be allowed to execute CGI/SSI programs. This is useful to block out "system" groups.
Can the wrapper successfully become the target user and group? Here is where the program becomes the target user and group via setuid and setgid calls. The group access list is also initialized with all of the groups of which the user is a member.
Does the directory in which the program resides exist? If it doesn't exist, it can't very well contain files.
Is the directory within the Apache webspace? If the request is for a regular portion of the server, is the requested directory within the server's document root? If the request is for a UserDir, is the requested directory within the user's document root?
Is the directory NOT writable by anyone else? We don't want to open up the directory to others; only the owner user may be able to alter this directories contents.
Does the target program exist? If it doesn't exists, it can't very well be executed.
Is the target program NOT writable by anyone else? We don't want to give anyone other than the owner the ability to change the program.
Is the target program NOT setuid or setgid? We do not want to execute programs that will then change our UID/GID again.
Is the target user/group the same as the program's user/group? Is the user the owner of the file?
Can we successfully clean the process environment to ensure safe operations? suEXEC cleans the process' environment by establishing a safe execution PATH (defined during configuration), as well as only passing through those variables whose names are listed in the safe environment list (also created during configuration).
Can we successfully become the target program and execute? Here is where suEXEC ends and the target program begins.

These 20 checks must all pass successfully for the program to be run. Many of the causes of problems with Perl CGI scripts are a failure to meet one of these rules. We can summarize certain aspects of the rules as follows:

  1. The script must exist and must have lines which end in newlines (\n not carriage returns \r).
  2. The script must be executable for the Apache web server (chmod 755 scriptname).
  3. The script must not be writable by other users (not 777).
  4. The owner of the script must exist on the system. (grep ^owner: /etc/passwd).
  5. The group of the script must exist on the system. (grep ^group: /etc/group).
  6. Neither the owner nor the group for the script may be 'root' or below UID 500 and GID 500.
  7. The script cannot be "Set GID" or "Set UID".

  8. Directory:
  9. The directory must exist.
  10. The directory must be readable and searchable by the Apache web server (chmod 755 directorypath).
  11. The directory must not be writable by other users (not 777).
  12. The owner of the script must be the same as the owner of the cgi-bin directory (ls -ld directorypath).
  13. The script must be in a cgi-bin directory that is known to the Apache web server (grep ^ScriptAlias /etc/httpd/conf/httpd.conf).
  14. The Apache web server must be configured to allow execution of scripts within the cgi-bin directory (directory container must contain options +ExecCGI).

What do the error messages mean?
The Apache web server will return error messages, depending on the status of the request. A normal delivery of a document will return a "200". Other values may have relavence to CGI problems. Below is a table listing the messages:

Context for CGI
Successful Client Requests
200 OK
201 Created
202 Accepted
203 Non-Authorative Information
204 No Content
205 Reset Content
206 Partial Content
Client Request Redirected
300 Multiple Choices
301 Moved Permanently
302 Moved Temporarily
303 See Other
304 Not Modified
305 Use Proxy
Client Request Errors
400 Bad Request
401 Authorization Required
402 Payment Required (not used yet)
403 Forbidden
The script does not have the correct permissions to be read and executed by the web server. Ensure that the cgi-bin directory is also readable and searchable by the web server. Both should be 755 in most cases.
Context for CGI
404 Not Found
The Apache web server cannot find your script. Unix/Linux filenames are case sensitive.
405 Method Not Allowed
406 Not Acceptable (encoding)
407 Proxy Authentication Required
408 Request Timed Out
409 Conflicting Request
410 Gone
411 Content Length Required
412 Precondition Failed
413 Request Entity Too Long
414 Request URI Too Long
415 Unsupported Media Type
Server Errors
500 Internal Server Error
Web server attempted to run script but failed, often due to an suExec violation (see above). Make sure scripts are uploaded in ASCII or text mode, not binary! Check the path to Perl in the sha-bang line of the script.
501 Not Implemented
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
505 HTTP Version Not Supported