Nginx home directories and PHP

I use nginx as my main HTTP server.  I want the users to be able to publish their own pages in a special directory (public_html) within their home directory. They should also be able to use PHP scripts if they want to. You can access the user webpage (that is the content of their public_html directory) with this URL: http://[server]/~[user]/. Here is a snippet of the configuration I use to do so:

index index.html index.xml index.php;

# PHP in home directory
location ~ ^/~(.+?)(/.*\.php)(.*)$ {
  alias /home/$1/public_html;

  try_files $2 =404;
  fastcgi_split_path_info ^(.+\.php)(.*)$;
  fastcgi_pass unix:/var/run/php5-fpm.sock;
  fastcgi_index index.php;
  fastcgi_intercept_errors on;
  include fastcgi_params;

  fastcgi_param SCRIPT_NAME /~$1$fastcgi_script_name;
}

# Home directories
location ~ ^/~(.+?)(/.*)?$ {
  alias /home/$1/public_html$2;
}

You can see here the two locations that match the user directories. The first one matches the PHP scripts and passes them to the FastCGI process manager. For more information, see PHPFcgiExample. Note that I use a UNIX instead of an INET socket. Why would you bother IP on localhost when you can use an UNIX socket? I also set the SCRIPT_NAME parameter to ensure that it is derived correctly from the user URL. This need to be fixed for pages that point to themselves. I also had to restart php5-fpm to ensure that the changes were taken into account.

 

4 thoughts on “Nginx home directories and PHP

  1. I had this problem as well, but the stuff at stack exchange wasn’t doing the job. After two days of hammering nginx config your blog post saved my day.

  2. Hi,
    I had to change the following to have it work on Ubuntu 16.04 :
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

    changed to :

    fastcgi_param SCRIPT_FILENAME /home/$1/public_html$fastcgi_script_name;

    Cheers,
    Thierry

  3. Hello.
    My name is Oleg.

    I would like show my fuul config.
    It don’t work.
    Maybe you can help me?

    server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;

    index index.php index.html index.htm index.nginx-debian.html;

    server_name ngninx.local;

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

    location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    # PHP in home directory

    location ~ ^/~(.+?)(/.*\.php)(.*)$ {

    alias /home/$1/public_html;

    try_files $2 =404;

    fastcgi_split_path_info ^(.+\.php)(.*)$;

    fastcgi_pass unix:/var/run/php7-fpm.sock;

    fastcgi_index index.php;

    fastcgi_intercept_errors on;

    include fastcgi_params;

    fastcgi_param SCRIPT_FILENAME /home/$1/public_html$fastcgi_script_name;

    }

    location ~ /\.ht {
    deny all;
    }
    # Home directories

    location ~ ^/~(.+?)(/.*)?$ {

    alias /home/$1/public_html$2;

    }

    }

    • Hello Oleg,

      There are some errors in the order in which you put the location blocks. The regex matches (those beginning with “location ~”) are evaluated sequentially and selected on first match.

      For example, say you have a request for “/~user1/index.php”. Then the first regex location block “location ~ \.php$” matches the URL, so it will be selected, and it will try to execute the PHP script from your root (/var/www/html).

      So you need to specify the regex in the configuration ordered from “more specific” to “less specific”. That is:

      1) PHP scripts in users directories
      “location ~ ^/~(.+?)(/.*\.php)(.*)$”

      2) Everything else (html, images, css, js, …) in users directories
      “location ~ ^/~(.+?)(/.*)?$”

      3) PHP scripts in your root
      “location ~ \.php$”

      Also you’d have to place “location ~ /\.ht” before all this to deny access to any file beginning with “.ht” (including backup such as “.htaccess~” or “.htaccess.old”, …). Speaking of that, “.htaccess” doesn’t really have anything to do with nginx, that’s apache stuff. So just to be sure you can also deny any file starting with a “.” with “location ~ /\. { deny all; }”. Most of the time these are supposed to be hidden files or backup that you don’t want to be accessible.

      There is more info about the location block selection algorithm here:

      http://nginx.org/en/docs/http/ngx_http_core_module.html#location

      And it’s also well explained here:

      https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms#matching-location-blocks

Leave a Reply

Your email address will not be published. Required fields are marked *