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?

  • nginx locations are exclusive. If your request ends up in location for PHP files, nginx does not look for other matching locations therefore nginx does not know anything about alias directive in userDir location. – Alexey Ten May 1 '14 at 22:37
  • Thanks. But when I've put the PHP part inside the UserDir part, it didn't change anything, SCRIPT_FILENAME was still mangled. – ckujau May 2 '14 at 8:36
1

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.

  • Wow, that's magic indeed. I'd have hoped that this could be done w/o rewrite tricks - it's only a userdir and rewrite rules (and if) always seem so fragile. Also, I cannot set autoindex inside the userdir anymore. But otherwise, this works, thanks! – ckujau May 1 '14 at 23:59
  • @ckujau see update – Alexey Ten May 5 '14 at 10:24
  • Thanks for the update. Sorry, it took me a while to find time to test this. Unfortunately, this isn't working here, I'm getting 404 errors when trying to access ~dummy/bar/index.php. I shall take this to an nginx mailinglist. Thanks for your input though! – ckujau May 31 '14 at 6:21
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

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.