1

I have a scenario with nginx/1.4.6 running on Ubuntu 14.04 but with php/5.2.10 inside a chroot Ubuntu 9.10 (Karmic Koala).

My issue is that all requests to php files result in the dreaded "No input file specified."

I have the site stored inside the chroot, so it is readable both from php inside the chroot jail and from nginx outside of the jail with this setup:

From nginx' point of view:
/var/chroot/karmic/var/www/domains/dummysite/web:
.         www-data:www-data drwxr-xr-x
index.php www-data:www-data -rw-r--r--
test.jpg  www-data:www-data -rw-r--r--

And inside chroot

From php's point of view:
/var/www/domains/dummysite/web:
.         www-data:www-data drwxr-xr-x
index.php www-data:www-data -rw-r--r--
test.jpg  www-data:www-data -rw-r--r--

And index.php is dead simple!

<?php
    echo '<h1>Hello World</h1> Foo bar...';
?>

I have started php-fcgi with spawn-fcgi from lighttpd using this command:

LANG=C chroot /var/chroot/karmic /usr/bin/spawn-fcgi -C 12 -a 127.0.0.1 -p 9000 -u www-data -g www-data -f /usr/bin/php5-cgi -P /var/run/fastcgi-php.pid

Nginx can successfully serve the static test.jpg, but php-fcgi fails to read index.php

# /etc/nginx/site-enabled/dummysite -> /etc/nginx/site-available/dummysite:

server {
    listen 80;
    root /var/chroot/karmic/var/www/domains/dummysite/web;
    server_name dummysite.wtf;

    location / {
        try_files $uri $uri/ /index.php?q=$uri&$args;
        index index.php index.html;
        allow all;
    }

    location ~ ^/index\.php {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_intercept_errors on;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        fastcgi_param SCRIPT_FILENAME /var/www/domains/dummysite/web$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT /var/www/domains/dummysite/web;
        include fastcgi_params;
    }
}

As far as I have understood, this should be the correct syntax. I have also tried with some variations such as $document_root$fastcgi_script_name, without SCRIPT_NAME or DOCUMENT_ROOT set and with SCRIPT_FILENAME relative to DOCUMENT_ROOT or the root inside the server block.

I have no open_basedir restrictions set in php.

Despite having maximum logging enabled in php and nginx, I get no workable information in either php.log, nginx.error.log or dummysite.wtf.error.log.

I have resorted to connecting to php-fcgi directly with the cgi-fcgi utility directly and this is the response I get:

env -i SCRIPT_NAME=index.php DOCUMENT_ROOT=/var/www/domains/dummysite/web SCRIPT_FILENAME=/var/www/domains/dummysite/web/index.php QUERY_STRING= REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000
Status: 404 Not Found
X-Powered-By: PHP/5.2.10-2ubuntu6
Content-type: text/html

No input file specified.

The same result applies to all calls with SCRIPT_FILENAME set to

  • /index.php
  • /web/index.php
  • /dummysite/web/index.php
  • /domains/dummysite/web/index.php
  • /www/domains/dummysite/web/index.php
  • /var/www/domains/dummysite/web/index.php
  • /karmic/var/www/domains/dummysite/web/index.php
  • /chroot/karmic/var/www/domains/dummysite/web/index.php
  • /var/chroot/karmic/var/www/domains/dummysite/web/index.php

And I have tried the same with various DOCUMENT_ROOT.

2
  • Long story short: you forgot to translate non-chrooted full path to chrooted, and, since chrooted php-fpm uses the latter one, got troubles.
    – drookie
    Nov 20, 2014 at 13:39
  • Well, no... I didn't forget to translate to chrooted path. In fact, I did just that, and it would have worked if I hadn't made two errors. One of them was fixed either by setting a new root (which I had tried but that didn't work because of another error), or omitting the include or moving the include to the top of my location block. But the real culprit was that I mixed up SCRIPT_NAME and SCRIPT_FILENAME. So, long story short: I mixed up SCRIPT_NAME/SCRIPT_FILENAME and had some issues with my variables being overridden by the non-chrooted path.
    – Xyz
    Nov 22, 2014 at 14:37

1 Answer 1

4

TL;DR

/etc/nginx/sites-enabled/dummysite -> /etc/nginx/sites-available/dummysite
...
location ~ \.php {
    root /var/www/domains/dummysite/web;
    fastcgi_pass 127.0.0.1:9000
    include fastcgi_params;
}
...

And

/etc/nginx/fastcgi_params
...
fastcgi_param SCRIPT_NAME $document_root$fastcgi_script_name;
...

Long solution

Ok, this is how I solved it (I thought it might come handy to someone). As php-cgi isn't very verbose I resorted to using strace to capture php's file operations to disk.

 sudo strace -p <pid-of-first-php-process> -p <pid-of-2nd-php> ... -p <pid-of-nth-php> -e trace=all -s 4096

Then I called the php-fcgi directly with:

env -i SCRIPT_NAME=index.php DOCUMENT_ROOT=/var/www/domains/dummysite/web SCRIPT_FILENAME=/var/www/domains/dummysite/web/index.php QUERY_STRING= REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000

And the interesting lines in the strace was

[pid 24822] read(3, "\v\tSCRIPT_NAMEindex.php\r\33DOCUMENT_ROOT/var/www/domains/dummysite/web\17%SCRIPT_FILENAME/var/www/domains/dummysite/web/index.php\f\0QUERY_STRING\16\3REQUEST_METHODGET\0", 152) = 152
[pid 24822] lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
[pid 24822] lstat("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
[pid 24822] lstat("/var/www/domains", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
[pid 24822] lstat("/var/www/domains/dummysite", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
[pid 24822] lstat("/var/www/domains/dummysite/web", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
[pid 24822] lstat("/var/www/domains/dummysite/web/index.php", {st_mode=S_IFREG|0644, st_size=31, ...}) = 0
[pid 24822] open("/index.php", O_RDONLY) = -1 ENOENT (No such file or directory)

Ok, so clearly, it successfully tried to lstat [...]/web/index.php (which has the correct 0644 permissions), but then it tried to open /index.php. This led me to experiment with SCRIPT_NAME, and voila!

env -i SCRIPT_NAME=/var/www/domains/dummysite/web/index.php DOCUMENT_ROOT=/var/www/domains/dummysite/web SCRIPT_FILENAME=/var/www/domains/dummysite/web/index.php QUERY_STRING= REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000
X-Powered-By: PHP/5.2.10-2ubuntu6
Content-type: text/html

<h1>Hello World!</h1> Foo bar...

So, my first problem was that my nginx config should read

        fastcgi_param SCRIPT_NAME /var/www/domains/dummysite/web$fastcgi_script_name;
#           see what i did here   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

To be honest; I have no idea why this is. I thought the purpose of SCRIPT_NAME is not to point to the file but merely state the name of the file. But I guess I must have misunderstood its purpose.

But, unfortunately, my issues where not over just yet. For when I tried to curl http://dummysite.wtf/, it still said No input file specified.

So, yet again, strace to the rescue!

[pid 24819] read(3, "\r\33DOCUMENT_ROOT/var/www/domains/dummysite/web\17%SCRIPT_FILENAME/var/www/domains/dummysite/web/index.php\v%SCRIPT_NAME/var/www/domains/dummysite/web/index.php\f\0QUERY_STRING\16\3REQUEST_METHODGET\f\0CONTENT_TYPE\16\0CONTENT_LENGTH\0177SCRIPT_FILENAME/var/chroot/karmic/var/www/domains/dummysite/web/index.php\v\nSCRIPT_NAME/index.php\v\1REQUEST_URI/\f\nDOCUMENT_URI/index.php\r-DOCUMENT_ROOT/var/chroot/karmic/var/www/domains/dummysite/web\17\10SERVER_PROTOCOLHTTP/1.1\21\7GATEWAY_INTERFACECGI/1.1\17\vSERVER_SOFTWAREnginx/1.4.6\v\tREMOTE_ADDR127.0.0.1\v\5REMOTE_PORT46644\v\tSERVER_ADDR127.0.0.1\v\2SERVER_PORT80\v\nSERVER_NAMEdummysite.wtf\17\3REDIRECT_STATUS200\17\vHTTP_USER_AGENTcurl/7.35.0\t\nHTTP_HOSTdummysite.wtf\v\3HTTP_ACCEPT*/*\0\0\0\0\0\0", 672) = 672

And right there is the answer, SCRIPT_NAME, SCRIPT_FILENAME and DOCUMENT_ROOT appears two times, the first time they are correct, the second time with an incorrect value. It turns out the include fastcgi_params directive in the nginx server block will insert these variables itself, and as I put this include statement last in my location block, it was effectively overriding my previous settings.

This is how I fixed this:

/etc/nginx/sites-enabled/dummysite -> /etc/nginx/sites-available/dummysite
...
location ~ \.php {
    root /var/www/domains/dummysite/web;
#   ^ This line will set the $document_root variable used later on
    fastcgi_pass 127.0.0.1:9000
    include fastcgi_params;
}
...

And in the fastcgi_params file that is included i changed one line to this

/etc/nginx/fastcgi_params
...
fastcgi_param   SCRIPT_NAME             $document_root$fastcgi_script_name;
# This is needed for chroot to work -> ^$document_root^ 
...

And finally, glorious success!

$ curl http://dummysite.wtf
<h1>Hello World!</h1> Foo bar...

This is one way to run a fatally old php version inside a chrooted jail on top of modern software such as ubuntu 14.04 LTS and nginx 1.4.x :-)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .