3

I have a fairly simple nginx/1.4.7 installation (from Debian/unstable) and I'm trying to get PHP scripts to run inside a UserDir.

server {
        listen          8083;                                
        server_name     sid0.local;
        index           index.php index.html;
        root            /data/www/sid0.local;

        location / {
                try_files $uri $uri/ =404;
        }

        # PHP-FPM
        location ~ \.php$ {
                include         fastcgi_params;
                fastcgi_pass    unix:/var/run/php5-fpm.sock;
                fastcgi_index   index.php;
        }

        # UserDir
        location ~ ^/~(.+?)(/.*)?$ {
                alias           /home/$1/www$2;
                autoindex       on;
        }
}

Accessing http://sid0.local/~dummy works, it lists the content of /home/dummy/www/ and I can access files there. Underneath ~dummy/bar is a file called index.php - yet, accessing http://sid0.local/~dummy/bar/ brings the dreaded "File not found." error (not a 404). The error.log has:

2014/04/30 23:07:44 [error] 4237#0: *9 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 192.168.0.103, server: sid0.local, request: "GET /~dummy/bar/ HTTP/1.1", upstream: "fastcgi://unix:/var/run/php5-fpm.sock:", host: "sid0.local:8083"

Now, many people seem to have this problem and some of them are even posting solutions, like making sure that SCRIPT_FILENAME is set to request_filename - but this is already the case (it's set in fastcgi_params).

However, running strace(1) against the nginx process gives (edited for readability):

4045  connect(16, {sa_family=AF_FILE, path="/var/run/php5-fpm.sock"}, 110) = 0
4045  writev(16, [{"\1\1\0\1\0\10\0\0\0\1\0\0\0\0\0\0\1\4\0\1\3T\4\0\f\0
      QUERY_STRING\16\3
      REQUEST_METHODGET\f\0
      CONTENT_TYPE\16\0
      CONTENT_LENGTH\0170
      SCRIPT_FILENAME/data/www/sid0.local/~dummy/bar/index.php\v\25
      SCRIPT_NAME/~dummy/bar/index.php\v\f
      REQUEST_URI/~dummy/bar/\f\25
      DOCUMENT_URI/~dummy/bar/index.php\r\33
      DOCUMENT_ROOT/data/www/sid0.local

As you can see, SCRIPT_FILENAME is NOT request_filename but instead document_root+fastcgi_script_name - hence the 404, of course.

So, I guess my question is: why is my SCRIPT_FILENAME mangled (I even set it to fastcgi_script_name, no luck) and how do I get PHP scripts inside a UserDir running?

ckujau
  • 667

2 Answers2

2

I would change root dir rather than using alias in location. It could look like this:

listen          8083;                                
server_name     sid0.local;
index           index.php index.html;

# Here is magic
set $root_dir /data/www/sid0.local;
rewrite ^(/~[^/]+)$ $1/ redirect;
rewrite ^/~(?<user>[^/]+)(.+) $2;
if ($user) {
    set $root_dir /home/$user/www;
}
root $root_dir;

# PHP-FPM
location ~ \.php$ {
    try_files $uri =404;
    include         fastcgi_params;
    fastcgi_pass    unix:/var/run/php5-fpm.sock;
    fastcgi_index   index.php;
}

Another version without rewrite:

listen          8083;                                
server_name     sid0.local;
index           index.php index.html;

root /data/www/sid0.local;

location ~ ^/~(?<user>[\w-]+)(?<path>/.*)$ {
    alias /home/lynn/tmp/site/$user/www$path;
    autoindex on;

    # PHP-FPM
    location ~ \.php$ {
        try_files $uri =404;
        include         fastcgi_params;
        fastcgi_pass    unix:/var/run/php5-fpm.sock;
        fastcgi_index   index.php;
    }
}

For some reason alias with named captures working, while with numeric references it fails. My guess, that numeric references are cleared somehow in nested location.

Alexey Ten
  • 1,639
  • 2
  • 12
  • 8
0

Based on Alexy Ten's answer, I placed the following configuration files in /etc/nginx/default.d/ as they are included by nginx.conf in my default install:

$ cat 00-index.conf 
index index.html;

$ cat 50-userdirs.conf
location ~ ^/~(?<user>[\w-]+)(?<path>/?.*)$ {
    alias /home/$user/www$path;
    autoindex on;
}

Notice the added ? symbol after the / symbol to match hostname/~user without a trailing slash. That fixes one 404 error.

If you are getting 403 errors due to SELinux, you will need to update your access rules:

# semanage fcontext -a -t httpd_user_content_t '/home/[^/]*/www/.*'
# for userdir in /home/* ; do restorecon -Rvi "$userdir/www" ; done
andrew-e
  • 173