Debugging tips for your CGI scripts
Updated Dec 29 at 09:34 CDT (first posted Sep 21 at 05:05 CDT) by Remi in CGI script, FAQ, Help, Python, Software - 18 comment(s)
Symptoms
So you've carefully written your CGI script, you transfer it to our servers and bang, it doesn't work !
You most likely get the dreaded "Internal server error" in your browser and if you look at the error logs in Apache, you probably see the infamous "Premature end of script headers".
What the heck is happening ?
The "Internal server error" in your browser and the "Premature end of script headers" message in the logs are Apache's way of telling you "There's something wrong with your script" ... Very helpful isn't it ... But don't panic, there are several things you can do to see what's causing the problem.
Put on your detective hat
Check the permissions
Regardless of which user will execute the script (either the "apache" user, or yourself if Apache is configure with SuExec - which is the case at WebFaction), that user will need the executable permission on the script *and* the directory. But that's not all ! With Apache there is such a thing as "too many permissions" ... This seemed very counter-intuitive to me at first and the only interpretation that I can think of for this is that Apache is basically thinking "this is not safe enough, I'm not going to run that script". In general, you can use 711 as the permissions for the script and the directory:
Try running the script from the command line
If the script doesn't run from the command line, it's not going to work from the browser. Here are a few things that can happen when you run it from the command line:
1. "bad interpreter: No such file or directory"
As seen here:
This is a common error and it usually happens when you transfered a file from Windows to Linux and didn't convert the "\r\n" into "\n". In that case, there is an extra character (invisible from a normal editor) on your shebang line and it's confusing the shell. One way to check if this is the case is to use the "hexdump" tool to see the exact bytes in your text file:
Notice the "0a0d" sequence ... This means that your lines end with "\r\n". In order to replace that with just "\n" you can either tell your ftp or sftp client to do the conversion for you, or you can use the "dos2unix" tool to do that for you:
Notice how the "0a0d" is gone and it's just "0a" now. Your script should work fine now.
2. "xxxxx: bad interpreter: No such file or directory"
As seen here:
This error means that the path that you specified on your shebang line doesn't exist. In the example, "/usr/local/bin/python2.6" doesn't exist. If I replace it with "/usr/local/bin/python2.5" then my script works fine.
A working script
Sometimes it's good to have a sample working script so that you have a good starting point to write your other scripts. Here is a sample script (and its permissions) that works:
Debugging tips
Checking if the script runs at all
Sometimes it's not even clear if Apache runs the script at all.
One simple trick you can use to check if the script is running at all is to make it create a file in /tmp from the very beginning:
You can then try to request the URL in your browser and if your script runs at all you should see a file called "foo" in /tmp.
Note that you can use a similar technique for writing debugging information from your script to a file.
Using the error logs
Anything your script prints on stderr will go in your Apache's error logs. For instance, if you use a python script and an error happens in your script, you will see the traceback in your Apache's error logs.
You can also manually write to stderr from your script and check the messages later from your logs. Here is an example:
Then you can request the URL in your browser. And now check the logs:
18 comments:
tail -f [filename]
and leave that running in another shell window.
that way I can debug the script in one window, and see the errors as I go along.. much faster
Say I've got a script printing:
$ ./test.cgi
Content-Type: text/plain
Hello, World!
but navigating to that script's URL still gives a 500. What then? (Because I'm actually experiencing this exact error.)
I've got a file, index.cgi, in directory "upload". I've set chmod 711 on index.cgi in that folder. Spits out desired HTML when I run it from an SSH window. However, pointing my browser to http://www.lillimuse.com/upload redirects to http://www.lillimuse.com/upload/upload (???) though there's no file by that name in the folder, and bypasses index.cgi, so I get a 404. Browsing to upload/index.cgi does the same thing - attempts to load upload/upload. Thoughts? Thanks!
Also, my preferred text editor, Edit+, lets you specify (PC|Unix|Mac) encoding for files, which is really helpful for development :)
Also, my preferred text editor, Edit+, lets you specify (PC|Unix|Mac) encoding for files, which is really helpful for development :)
-----BEGIN-----
#!/usr/local/bin/python2.5
print "Content-Type: text/plain"
print "Hello, world"
-----END-----
However, I get the ol' 500 error and Premature end of script headers in the log when I try run from the browser.
I have chmod'd both the directory and my test.cgi
Any suggestions on where to look next?
Thanks
Remi.
You should ask your question in our forum or one of the language that you wrote the script in's mailing lists. No one will be able to help without seeing lines 30 and 56 of your script, at least, not without playing a game of twenty questions. :)
I tried doing this in .htaccess:
AddHandler cgi-script ru
But I get this:
[Mon Jan 19 23:04:44 2009] [error] [client 207.216.160.210] /usr/bin/env: rackup: Permission denied
The script starts with:
#!/usr/bin/env rackup
..
And yes, it runs stand-alone, too.
#!/home/my_username/bin/rackup
If that doesn't seem to help, then please sign in to the control panel and use the Help menu to open a support ticket so that we can take a closer look.
Hope that helps!
Looks like my script is being intepreted by /bin/bash, even though it isn't supposed to be. I'll open a support ticket.
[octet@web65 ~]$ ./webapps/staticcgi/octet.ru
./webapps/staticcgi/octet.ru
/bin/bash
[octet@web65 ~]$ head webapps/staticcgi/octet.ru
#!/home/octet/bin/rackup
echo $0
echo $1
echo $SHELL
exit 1
use Rack::Reloader, 0
use Rack::ContentLength