nginx and nested locations

Another quick one for the blog. I was moving around some apps from subdomains to my main domain to take advantage of the new SSL-enabled web, and I needed some schooling about nginx once more to get things right. Here's one bit about locations and nesting.

From http://foo.mydomain.net to https://mydomain.net/foo

I have a few things going on under subdomains that I wanted to move off to my main domain as subpaths instead. As such I have a /etc/nginx/sites-enabled/foo configuration like this:


server {
        root /srv/somewhere/over/the/rainbow/www;

        index index.php index.html index.htm;

        server_name foo.mydomain.net;

        access_log /srv/somewhere/over/the/rainbow/log/access.log;
        error_log /srv/somewhere/over/the/rainbow/log/error.log info;

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

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

I wanted to move things off to /etc/nginx/sites-enabled/main, which has configurations for location / {...} and whatnot. Naturally, I thought I could get away with doing this:


        location /foo/ {
                alias /srv/somewhere/over/the/rainbow/www/;
                index index.php;

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

But alas, requests for http://mydomain.net/foo/blah.php returned 404 instead of my expected app.

Nesting prefix and regex based locations

Reading about nginx location again, I noticed this:

To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

I was under the impression that the prefix-based locations will also nest their last match with other location blocks within them, but apparently they do not. Hence the configuration becomes


        location /foo/ {
                alias /srv/somewhere/over/the/rainbow/www/;
                index index.php;

                location ~ /foo/*\.php$ {
                        include snippets/fastcgi-php.conf;
                        fastcgi_pass unix:/var/run/php5-fpm.sock;
                }
        }

Taking out the location ~ /foo/*\.php$ { ... } block from the nest will not work, which is consistent with the statement above.

This is further validated in this post with


   location /app1/ {
       # something special for app1 here, e.g.
       # access control
       auth_basic ...
       access ...

       location = /app1/login {
           # something special for /app1/login,
           # eveything from /app1/ is inherited

           proxy_pass ...
       }

       location ~ \.jpg$ {
           expires 1m;
       }
   }

Handling transitions from old to new location

After getting schooled and confirming it all works, now I just have to change my old subdomain configs to just use a return:


        return 301 https://mydomain.net/foo$request_uri;

And I'm all set.