“No input file specified” or “Primary script unknown” in the error log is one of the most frequently encountered issues in nginx+PHP.
People on serverfault and in the #nginx IRC channel asks for help with this so often that this post is mostly to allow me to be lazy and not have to type up the same answer every time.
This is actually an error from PHP and due to display_errors being 0ff people will often just get a blank page with no output. In a typical setup PHP will then send the error to stderr or stdout and nginx will pick up on it and log it in the nginx error log file. Thus people spend a ton of time trying to figure out why nginx isn’t working.
The root cause of the error is that PHP cannot find the file nginx is telling it to look for, and there are a few common cases that causes this.
Wrong Path Sent to PHP
The most common reason at the time of writing happens because a user uses a horrible tutorial found via google instead of actually understanding nginx. Reading my nginx primer will equip you to actually solve this on your own but since this post is actually dedicated to the error I’ll cheat this once and allow you to be lazy by just giving you the full solution.
Nginx tells PHP about the file to execute via the SCRIPT_FILENAME fastcgi_param value. Most examples in the wiki should define this as $document_root$fastcgi_script_name. The horrible tutorials will often hard code the path value but this is not desirable as we don’t want to duplicate information and invite future screw ups. So you’ve gone with the $document_root$fastcgi_script_name option and suddenly it’s no longer working.
This happens because nginx has 3 levels of inheritance commonly referred to as blocks, these being http, server and location, each being a sub-block of the parent. Directives in nginx inherit downwards but never up or across, so if you define something in one location block it will never be applied in any other location block under any circumstance.
Typically users define their index and root directive in location / because a tutorial told them to. So when they then define SCRIPT_FILENAME using $document_root the root directive is not actually defined and thus the SCRIPT_FILENAME value becomes just the URI making PHP look at the root server dir.
The simple solution here is to just define the directive in your server block. (or http block even!) Generally the higher up your can define a directive the less duplicate directives you’ll need.
Incorrect File Permissions
Most people don’t really believe me when I tell them their file permissions are incorrect. They’re looking at the damn permissions and the PHP user can read the file just fine! Sadly, this shows a lack of understanding of Unix user permissions. Being able to read a file is not enough, a user must also be able to traverse to the file.
This effectively means that not only should the file have read permission, but the entire directory structure should have execute permission so that the PHP user can traverse the path. An example of this:
Say you have an index.php file in /var/www. /var/www/index.php must have read permission and both /var and /var/www must have execute permissions.
Using Alias and $document_root
It is fairly common to define SCRIPT_FILENAME as $document_root$fastcgi_script_filename; However, $document_root does not account for the alias directive and will thus result in an incorrect path being sent. It is preferable to define SCRIPT_FILENAME as such:
fastcgi_param SCRIPT_FILENAME $request_filename;
This accounts for alias and ensures proper path is sent. One note about this is that $request_filename does not account for fastcgi_index, but you only use this index if you send a request ending in / to PHP. If you use the standard PHP location ~ \.php$ then you will never use the fastcgi_index directive.
Chrooted Environment
If your PHP lives in a chrooted environment that nginx does not, then they basically have 2 different roots and the file path that nginx reports to PHP will not resolve to the actual file. A simple example to make this obvious:
Lets say you request phpinfo.php, nginx looks in your defined root and finds this file in: /home/user/public_html/phpinfo.php
The PHP process for user is chrooted to only have access to his directory for security reasons, so as far as PHP knows the root of the server is at /home/user. Therefore when nginx reports the file path PHP will look in: /home/user/home/user/public_html/phpinfo.php.
Either make sure both nginx and PHP has the same chroot or make sure you rewrite your internal URI before you fastcgi pass to PHP.
Open Basedir Restriction
PHP has the option to limit file access to certain directories defined in your php.ini. Some distributions might preconfigure this option for their packaging system.
SCRIPT_NAME Versus SCRIPT_FILENAME
Fastcgi has two parameters which are quite similiar in name, make sure that you’re not confusing the SCRIPT_NAME variable for the SCRIPT_FILENAME one. SCRIPT_FILENAME tells fastcgi the location of the script to execute while SCRIPT_NAME merely tells the name of the script.
51 Comments. Leave new
Hey there!
I think you were it who telled me to read this yesterday in nginx-irc.
What i wan’t to say is in first line thanks, i’m on the way to understand how nginx work.
But there is one thing i really have to ask.
Do you mean the root-directive should be put from location – block to the server – block?
My english isn’t as good in some specific “slangs”, so i don’t really know.
Yeah you want your root directive in your server block as the $document_root variable is then available in all your location blocks. So if you pass to a backend and have to provide a path to the file to execute you can then use the $document_root variable and avoid duplicating your paths.
[…] instead try to execute the /index.php file which doesn’t exist and thus return 404 and “no input file specified”The best way, in my opinion, is to use the fastcgi_split_path_info directive in Nginx to handle the […]
Thanks! Clearly written about the problem and I solve it.
I wish I’d read your Nginx Primer when I first come to nginx, so I don’t need to waste my time on solving this problem.
Anyway, I’m reading your Nginx Primer now 🙂
Hi Martin
Thanks for the explanation.
May I ask you one question though? Why do people use SCRIPT_FILENAME = $document_root$fastcgi_script_name
I’ve installed Nginx from a package, and this is a default FastCGI param:
fastcgi_param SCRIPT_FILENAME $request_filename;
Why would I change it to $document_root$fastcgi_script_name
Many thanks
$request_filename is actually just a shortcut for the document root (or alias) + the request URI. This means that so long as you do not rely on fastcgi_index then you can safely use $request_filename instead of $document_root$fastcgi_script_name.
The important part is still that you keep root defined in server context so that it’s available in your PHP location.
Thanks for that reply Martin.
One more question: do you think there’s a lot of overlap between Nginx, Varnish and the W3 Total Cache WordPress plugin?
For example, does the W3 page cache overlap with the Varnish cache? Intuitively, I imagine Varnish cache is quicker because (in my case – with malloc) it’s using memory. I’d like to reduce overlap so am wondering if the perfect WordPress solution could do without a cache plugin, maybe just a minify plugin.
Then there’s browser caching, Gzip and headers. It seems you can set these from Nginx, Varnish or W3. I imagine a lot of installs out there are duplicating Gzip across Nginx and W3.
I’ve looked through the nginx.conf that W3 produces and it’s quite a mess. To keep things lightweight and simple, I’m thinking about ditching W3. Do you think there’s anything really positive that W3 achieves, other than minify, that’s not possible with Nginx or Varnish?
There’s a lot of overlap between Nginx and Varnish, so much that I don’t even bother with Varnish at all, I just cache with Nginx. Application layer caching that is W3 Total Cache is completely unrelated, though, and I prefer using Memcached for that so it uses memory as well. As for WordPress, it really does need a caching plugin, it’s absolutely horrible without it. W3 with APC or Memcached storage engine is very clean and very easy to use and makes it so much faster.
Thank you for your explanation!I know your means,But i still have some question.I have two work directory,one is D:\NET,one is E:\NET,i use alias or root in the location block,this two location have the same server block,so the server block have one root,when i vister the php files in D:\NET directory,i get a “No input file specified” error at then when i vister php files in E:NET directory,vice versa,In your means,because the root is in D:\NET,not E:\NET,how can i vister the php file at the same time at all of alias or root of location block?
Hi Martin,
I am wondering if there are any other known causes of this error, because I am getting “No input file specified.”, even though the paths and permissions seem fine. I am sorry to reward your excellent blogging by treating you like tech support, but I suspect that if I asked this on a PHP mailing list it might get ignored as an “nginx issue”.
Why do I think my config is fine? The “root” directive is in the server block; in fact if I use tcpdump to evesdrop on the fastcgi traffic, I see ….SCRIPT_NAME/var/www/index.php…”, which looks fine too me. Similarly, the permissions are fine; I can become the same user as the PHP process and “cat” the source file.
So it looks to me like it’s an issue with PHP itself, but I can’t prove it. Frustratingly, I have made all this work without any trouble at all on other machines!
Cheers.
Hi. I just fixed the problem I mentioned abovfe! Mea Culpa I guess, but perhaps this is worth adding to your post: Debian’s version of /etc/nginx/fastcgi_params defines SCRIPT_NAME but not SCRIPT_FILENAME. If I define the latter, things start to work.
Is this a Debian bug? Or is it something else?
It’s not a bug really. fastcgi_params never included SCRIPT_FILENAME from the source, fastcgi.conf does, though. You could kind of consider fastcgi_params as deprecated. If anything it’s a problem of the fastcgi protocol that it defines two variable names which are so close together that people will misread them as being one and the same.
my wordpress website does not seem to work with ur solution.. i have defined the complete root in the location block..
I still get the error “No Input file specified ” for this case
http://lotrix.com/wp-admin
but I dont get the same error for the below case
http://lotrix.com/wp-admin/
– just the forward slash is missing and nothing else.. what do you think might be the problem….
Can’t help you unless you put a link to a pastebin of your config.
I tried to follow this closely, but am having several problems. I continue to get the “No input file specified” error for valid files, and on top of that, nothing is redirecting properly. I’ve fiddled endlessly, and looked for help on IRC, with no luck.
Would be extremely grateful for a pointer. Relevant config and brief discussion is at
http://paste.scsys.co.uk/183650
Thank you.
Your problem is that you have misunderstood the purpose of the root directory. The documentation here: http://wiki.nginx.org/HttpCoreModule#root states that the full URI is always appended to the root directory. So you end up looking in /usr/local/www/data/blog/blog. Fix your root and it should work.
Hmm. I had previously looked at that doc very closely, in another context, but I didn’t really get it until now.
But I’m afraid making this change still hasn’t fixed it. I changed the root to /usr/local/www/data, and also tried changing location to “/blog/” (with closing slash), and I’m still getting 404’s on bogus pages, and “No input file specified” for existing pages.
Is there a way I can see exactly what file nginx is looking for? I tried changing the error_log to “info”, but these things aren’t showing up as errors in the logs.
Thanks.
Thanks for the informative post. Unfortunately I still have the problem even though I believe everything mentioned in your post is set correctly. I posted the full details in the nginx forum here
http://forum.nginx.org/read.php?15,225132
but I didn’t receive a reply. I’m pretty new to linux and assume it’s a simple mistake but I have no idea what it is.
Thanks
You’ll want to check the permissions on /var as well, not just /var/www. If those are fine then next step is checking whether you’re setting a chroot in php-fpm as that affects the path you should be sending to PHP.
Is there a way to redirect the “no input file specified” to a 404 page? This page is the only real relevant page turned up by google.
The best I can think of is using httpd to serve up php which then can serve up error pages, but that eliminates the advantage of using nginx at all.
Cheers,
Peter M Dodge
Certainly, but not perfectly. If you check the headers for these requests you’ll see that PHP is returning a 403 status header. This means that if you use fastcgi_intercept_errors along with error_page in your PHP passing location then you can handle the 403 errors fine.
The problem is that you cannot tell the difference between no input file specified and 403s returned by your real application. If your nginx hosting server also have the PHP files then a simple try_files will be able to ever prevent the no input file specified error from even showing in the first place by just not passing a non-existent file to PHP.
Thankyou so much,
I couldn’t find out what the issue was and this tutorial helped me understand unix and nginx so much better, that i worked out the problem myself (allowed directories in php.ini, something i would normally need to ask of a forum)
Thankyou!
So…
I’m ashamed to say that your tuto saved my ass.
I understood nginx and what I was doing in the config much better and solved my problem in 2 seconds (after searching the web for an hour).
Thanks!
I was having similar issues, and even tried all your steps.
One extra thing to try which helped me was to check you have cgi.force_redirect = 0 set in php.ini
Hope that helps!
cgi.force_redirect is an Apache only feature, so yes it definitely needs to be disabled whenever you don’t use mod_php.
[…] one of the potential errors that might show up. For this example I will use the often encountered “Unable to open primary script” […]
I cannot run info.php file in my webserver. I dont know what else to do. This is my sites-available/default
http://pastebin.com/WDnqLwFy
Nothing wrong with the config you pasted. Please check into your file permissions or provide more details. “cannot run info.php file in my web server” is not a useful error description.
May i know which file permission?
I just create a simple php file that show php info, but even that file cannot be viewed, it just show “No input file specified”
It is specified in this very blog post how. If you don’t know which permissions to set then please hire a server admin as that is beyond what I’m comfortable helping you with in a blog post.
I changed the /usr/share/nginx/html permission to www-data, but still the same error appear
Nice post!
I really forgot about permission stuff.
I tried to follow your advice with my wordpress installation, but somehow without luck. The nginx-config is on http://pastebin.com/4yTMbvCz and the nginx-debug-level is on http://pastebin.com/8qUELibz. The file in the SCRIPT_FILENAME says:
root@arm:/var/log/nginx# ll /usr/share/nginx/wordpress/wp-admin/install.php
-rwxrwxrwx 1 www-data www-data 10447 Jun 30 13:18 /usr/share/nginx/wordpress/wp-admin/install.php*
So I guess the permissions are proper resp. more then sufficient. Would you mind to give a helping hand?
Thanks for sharing those tips! I can’t believe it, I had to spend a whole day trying to figure out why I was getting the “No file specified”. Turned out that it was the latter –
open_basdir
restrictions. Commenting it out in the php.ini fixed the issue for me.Thanks again!
root@test:~ # grep SCRIPT_FILENAME /usr/local/etc/nginx/nginx.conf | grep -v #
fastcgi_param SCRIPT_FILENAME $request_filename;
root@test:~ # grep ^open_basedir /usr/local/etc/php.ini
root@test:~ # su -m www
www@test:~ % file /usr/local/www/nginx/php/phpinfo.php
/usr/local/www/nginx/php/phpinfo.php: PHP script, ASCII text
www@test:~ %
and yet still “No input file specified.”
Could you give a pastebin link to your config?
sure, pastebin url is: http://pastebin.com/pz7eR53J
Hi Alexus,
You have the root defined in the location block which means it’s not available in your PHP block. I cover this in my primer and in the Wrong Path Sent to PHP section. I see that you use $request_filename, however, this variable still uses the root or alias directive to construct the path so it should still be defined in server context – not location context.
thank you for your reply, your blog’s post was very interesting) i wish if i could nginx into some sort of debug mode where I can see what some of those variables are equivalent to, like $request_filename it’d probably help it solve a lot quicker.
turns out the problem was in “root” being specified in almost every “location” while it was only suppose to be defined once in “server” block.
Saved my time today … thanks. SS
Thank you!!! Afeter looking for 2 hours I’ve found your web. Very clear explanation.
P.D.: I’m guilty of a “copypasting” tutorials. That was my error 🙂
now, thanx a lot for the ‘lazy walk’ 😉 …it indeed solved my initial trouble getting php to work via fcgi 🙂
… moreover, finally migrating from apache, your primer on nginx configuration as well pre-answered some imminent questions before actually stepping over the tripwires
bigup for the nice job, really helped a lot! 🙂
Thanks _A LOT_ for this usefull information about “Using Alias and $document_root”. Two days lost troubleshooting nginx configuration, changing parameters and trying to understand what was going on.
Now it’s running like a charm.
Best regards,
Ignacio
Hey! i have problem with my page too. After php version update i got error like this “502 Bad Gateway
nginx/1.6.2”
Thx. The open_basedire fix my question.
Martin, at first i want to thank you for this great information on your blod *thumbs-up*
I didn’t find the culprit and noone on #nginx channel was able to help me either, yet. You pointed at least to the right direction by explaining the difference of fastcgi.conf and fastcgi_params. My issue and configuration is explained here ==> http://p.ngx.cc/f414b76106e81c21
You said, that only “fastcgi_param SCRIPT_FILENAME $request_filename;” will take the use of “alias” into consideration so it can executed by fastcgi, is that correct? How do I modify my configuration to take also into account …
http://trac.nginx.org/nginx/ticket/321
and
http://wiki.nginx.org/PHPFcgiExample
which suggest NOT to use “try_files” but instead use “if” even then where nginx says that IfIsEvil ?
I’m kinda confused and cannot get this stuff to work and my goal is:
– I want to access all three webapps, and https://example.tld/webapp3/remote.php/webdav should also work (webapp3 is owncloud in my example).
– I want to have the best security context possible so attackers cannot upload and execute malicious code as explained here https://nealpoole.com/blog/2011/04/setting-up-php-fastcgi-and-nginx-dont-trust-the-tutorials-check-your-configuration/
– When I remember correctly I should use “cgi.fix_pathinfo = 0” in php.ini, right? that’s my actual setting.
– I was also told to use the “split_path” configuration as shown in my actual nginx configuration.
I would be very glad to hear your comments on that and how you suggest me to solve that. Any help appreciated.
Thank you so much in advance.
Martin awesome info and explanation, you mad my day. Thanks a lot.
– I am very new in Nginx…
– I am trying to create multi site using Drupal 7, Nginx on ubuntu 14.4.
– I am applying settings for multi site in given path: “/etc/nginx/sites-enabled/default”
– I saved my drupal setup in: “/var/www/drupal”
– given below is the code, which i am using in “/etc/nginx/sites-enabled/default” file
server {
#listen 80 default_server;
listen [::]:80 ipv6only=off;
root /var/www/drupal;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$args ;
}
location ~ ‘\.php$|^/update.php’ {
fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
#NOTE: You should have “cgi.fix_pathinfo = 0;” in php.ini
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_intercept_errors on;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
}
– I am trying this URL http://mydomain.com/site1, but it redirecting me to http://mydomain.com/install.php
– I need to create URL like: http://mydomain.com/site1.
Thank you so much in advance. Reply please
You’re probably better off asking complex questions like this on server fault or stack overflow.
[…] fastcgi_param SCRIPT_NAME of Nginx default configuration file. Some of them say pretty well, like this. I'm not mean these articles are wrong, but the modifying of fastcgi_param SCRIPT_NAME do not solve […]