Running CGI Scripts on Nginx

Created by: Lester Caine, Last modification: 22 Mar 2025 (09:07 GMT)

Need to document the work that I did on getting fcgiwrap actually working.

Key to this was the error message "run-fcgiwrap[19348]: Cannot get script name, are DOCUMENT_ROOT and SCRIPT_NAME (or SCRIPT_FILENAME) set and is the script executable?" which was hidden away on the main messages log. And that switched the target of my playing.

But in reality I'd missed a key element in the main nginx config file. While I had all of the web hosting material assigned to nobody:nobody as a user:group, this had not been set in nginx.conf and as a result a number of things were not accessable. The main problem here was that the while fcgiwrap.socket was set to the right user, nginx was not actually running as that user. Drop the right user entry as the first line of the config file and that particular hickup was cleared, and the scripts started to work, and the following actually works ...

The configuration files for the fcgiwrap service have two elements, one for the socket to be used and the second for the service itself. Both of these are found in /usr/lib/systemd/system/ with the socket config fcgiwrap.socket

[Unit]
Description=fcgiwrap Socket

[Socket]
SocketUser=nobody
SocketGroup=nobody
SocketMode=0660
ListenStream=/run/fcgiwrap.socket

[Install]
WantedBy=sockets.target

and the service config fcgiwrap.service

[Unit]
Description=Simple CGI Server
After=nss-user-lookup.target fcgiwrap.socket
Requires=fcgiwrap.socket

[Service]
EnvironmentFile=-/etc/sysconfig/fcgiwrap
Type=simple
ExecStart=/usr/sbin/run-fcgiwrap
User=nobody
Group=nobody

[Install]
Also=fcgiwrap.socket

From which it will be obvious that while these were configured to be used by the nobody user, without the matching "user nobody nobody;" in nginx.conf things did not match up. It only became a problem because of the SocketMode setting block even root from using the socket.

In addition to the two config file, a third file provides the environment information and as EnvironmentFile indicates, this is in the /etc/sysconfig folder. It only actually provides two settings, but since the second one directly flags a 403 error - which I was seeing - it added to the missunderstandings.

## Path:	Network/WWW
## Description:	Settings for fcgiwrap
## Type:	integer
## Default:	1
## ServiceReload: fcgiwrap
#
# The fcgiwrap service is used to spawn FastCGI worker
# processes that will invoke FastCGI scripts when the
# web server needs to execute them.
#
# Number of FastCGI workers to spawn
FCGI_WORKERS="1"

## Type:	string
## Default:	""
## ServiceReload: fcgiwrap
# A space-separated list of allowed CGI programs.
#
# If this is non-empty, attempts to call a CGI program not
# in the list will cause a HTTP 403-Forbidden error.
# Specify programs with full path, wildcards don't work.
# Paths need to match the script name passed by the server
# exactly.
FCGI_ALLOWED=""

It would be nice at some point to actually set FCGI_ALLOWED, but for now it should not be blocking any script.

Having got these service running, and knowing that fcgi was working anyway since the php-fpm services all use it and were working, the next step which I'd actually configured before playing with the socket and service, is an extra section in the vhost.conf file for the LSCES website.

    location /cgi-bin/ {
		gzip 			off;
        root			/srv/website;
        fastcgi_pass	unix:/var/run/fcgiwrap.socket;
        fastcgi_param	DOCUMENT_ROOT /srv/website/cgi-bin;
        fastcgi_param	SCRIPT_FILENAME	$document_root$fastcgi_script_name;
        include 		fastcgi_params;
    }

This is essentially identical to the php section of the config file apart from the DOCUMENT_ROOT entry. Until that was added I could not get the test script to run at all. I think in part this is due to the split of the folders between the location and root section while the full path is needed for DOCUMENT_ROOT. I'd seen various comments in the search engine results about if the cgi-bin element should be used in 'root', but since it is the location, then the root has to be the containing element.

There are a few little things I've had fun with in relation to the quick test.cgi script I was using initially, but I'll expand on that elsewhere. The next step is to get the target script working ... mapserv ... and that is where I'm off to next. MapServ Configuration and Data