Nginx, FastCGI, Wordpress Permalink & "No Input file specified"
If you have spent any time recently look into the state of web servers then you know that nginx is getting recommended as the replacement for apache left, right and center. Apache has a rich history, platform extensive, and highly extensible, and while these are great traits it’s 15 years of legacy code hasn’t seemed to keep pace with some of the modern design patterns such non-blocking i/o and simple configuration. To apache developers’ credit it is built to support a wide array of architectures and operating systems.
There is definitely a fair amount of information out there on how to get nginx running with WordPress via FastCGI. Slicehost, my current hosting provider, offers a wealth of articles on setting up nginx along with a rails cluster. I followed several other articles in getting FastCGI working through spawn-fcgi with requisite init scripts to ensure everything starts up properly. Everything was working great until I enabled pretty permalinks and then got the unfortunate error:
No input file specified.
I understood this to mean FastCGI could find the script attempting to be called, but couldn’t immediately see why that was the case. In the end it was something simple and obvious.
My initial configuration server configuration looked something like:
server {
listen 80;
...
location / {
# this serves static files that exist without running other rewrite tests
if (-f $request_filename) {
expires 30d;
break;
}
# this sends all non-existing file or directory requests to index.php
if (!-e $request_filename) {
rewrite ^.+?(/.*\.php)$ $1 last;
rewrite ^ /index.php last;
}
}
location ~ .php$ {
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html/www/public$fastcgi_script_name;
root /var/www/html/www/public;
}
}
And searching there were other suggestions for the rewrite as:
# this sends all non-existing file or directory requests to index.php
if (!-e $request_filename) {
rewrite ^(.+)$ /index.php?q=$1 last;
}
Which made no difference in the error condition. As I said in the end, the problem was something obvious. In my configuration, the wordpress installation is not at the root of the web server, rather it is in a subdirectory called blog. Therefore, with the initial configuration when a path could not be found, rather than call the wordpress index.php script located at /blog/index.php, it was calling just /index.php which initially didn’t exist. Had it existed, I probably would have quickly see which file was getting called and how to address. The change was to set up the wordpress rewrite information in the correct location block. The updated configuration became:
location /blog {
# this serves static files that exist without running other rewrite tests
if (-f $request_filename) {
expires 30d;
break;
}
# this sends all non-existing file or directory requests to index.php
if (!-e $request_filename) {
rewrite ^.+?(/.*\.php)$ $1 last;
rewrite ^ /blog/index.php last;
}
}
I haven’t yet configured out the “No Input file specified” when a bad php url is used, but that will probably be done shortly.