Nginx Library

A repository of Nginx-related articles

Resolving "No input file specified" error

If you are using nginx with php-cgi and have followed the standard procedure to set it up, you might often get the “No input file specified” error. This error basically occurs when the php-cgi daemon cannot find a .php file to execute using the SCRIPT_FILENAME parameter that was supplied to it. I’ll discuss about the common causes of the error and it’s solutions.

Wrong path is sent to the php-cgi daemon

More often than not, a wrong path (SCRIPT_FILENAME) is sent to the fastCGI daemon. In many of the cases, this is due to a misconfiguration. Some of the setups I have seen are configured like this :

server {
    listen   [::]:80;
    server_name  example.com www.example.com;
    access_log  /var/www/logs/example.com.access.log;  

    location / {
        root   /var/www/example.com;
        index  index.html index.htm index.pl;
    }

    location /images {
        autoindex on;
    }

    location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /var/www/example.com$fastcgi_script_name;
        include fastcgi_params;
    }
}

Now, there are many things wrong with this configuration. An obvious and glaring issue is the root directive in the location / block. When the root is defined inside the location block, it is available/defined for that block only. Here, the location /images block will not match for any request because it does not have any $document _root defined and we will have to redundantly define root again for it. Obviously, the root directive should be moved out of the location / block and defined in the server block. This way, the location blocks will inherit the value defined in the parental server block. Of course, if you want to define a different $document_root for a location, you can put a root directive in a location block.

Another issue is that the value of the fastCGI parameter SCRIPT_FILENAME is hard-coded. If we change the value of the root directive and move our files somewhere else in the directory chain, php-cgi will return a “No input file specified” error because will not be able to find the file in the hard-coded location which didn’t change when the $document_root was changed. So, we should set SCRIPT_FILENAME as below :

fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

We should keep in mind that the root directive should be in the server block or else, only the $fastcgi_script_name will get passed as the SCRIPT_FILENAME and we will get the “No input file specified” error.

The file actually does not exist

What happens here is that, even when Nginx receives the request to serve a non-existent file with a .php extension, it passes the request to php-cgi. This happens because Nginx does not check for the file, it only checks if the REQUEST_URI ends with a .php. Php-cgi, while trying to processs the request, finds that the php file does not exist at all. Hence it sends a “No input file specified” message with a “404 Not Found” header.

We can intercept the request for the non-existent php file and show a 404 page.

First, find out the version of nginx you are using.

nginx -v

You’ll get an output like this :

nginx version: nginx/0.7.67

If php-cgi is running on port 9000, you’ll have something like this in your vhosts file :

location ~ .php$ {
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME ....
    ...................................
    ...................................
}

Since nginx versions less than 0.6.36 doesn’t have the try_files directive, we’ll have two versions of the code.

For nginx 0.6.36+

We’ll use try_files here to catch non-existent URLs and display an error page.

location ~ .php$ {
    try_files  $uri =404;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME ....
    ...................................
    ...................................
}

Here we are checking for the existence of the .php file before passing it to the fastCGI backend. If the file does not exist, we return a 404 Not Found page.

For older versions :

location ~ .php$ {
    fastcgi_intercept_errors on;
    error_page  404  /path/to/404.htm;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME ....
    ...................................
    ...................................
}

Here the fastcgi_intercept_errors asks the fastCGI backend to return error statuses to Nginx so that Nginx can respond with a custm 404 page. The error_page directive defines a custom 404 page. Note that this will work for both older and newer versions of Nginx, but personally I think the try_catch method is cleaner.

Permissions are not set correctly

Permissions are not supposed to be much of a headache for executing PHP files. Apparently, we only need to make sure that the user the fastCGI backend is running as, has read permissions for the file. But it is often overlooked that a user also needs execute permissions for every parent directory of a file to chdir to that file. For example, say a file is located at -

/home/steve/files/req.txt

The user needs to have read permissions for the file as well as execute permissions for /, /home, /home/steve and /home/steve/files.

I have covered most of the common issues that cause this error. If you have something else, feel free to leave a comment.

If you find this article helpful, please consider making a donation.

Comments