Nginx wildcard/regex in location path

The Nginx config I have throws 404 for .php like:

## Any other attempt to access PHP files returns a 404.
location ~* ^.+\.php$ {
    return 404;
}

However I have some index.php file in subfolder that I want to run. The current config is like:

location = /sitename/subpage/index.php {
    fastcgi_pass phpcgi; #where phpcgi is defined to serve the php files
}

location = /sitename/subpage2/index.php {
    fastcgi_pass phpcgi; 
}

location = /sitename/subpage3/index.php {
    fastcgi_pass phpcgi; 
}

it works perfectly, but the issue is duplicate locations and if there are lots of subpages then the config becomes huge.

I tried the wildcard like * and some regex, which says the nginx test passed but doesn't load the page i.e. 404. What I tried are:

location = /sitename/*/index.php {
    fastcgi_pass phpcgi;
}

location ~* ^/sitename/[a-z]/index.php$ {
    fastcgi_pass phpcgi;
}

Is there any way I can have some pathname in the location as regex or wildcard?


Solution 1:

The = modifier in location block is an exact match, without any wildcards, prefix matching or regular expressions. That's why it doesn't work.

On your regex attempt, [a-z] matches a single character between a and z. That's why it doesn't work for you.

You need to have your locations set up like the following. Note the order of location statements. nginx picks the first matching regex condition.

location ~ ^/sitename/[0-9a-z]+/index.php$ {
    fastcgi_pass phpcgi;
}

location ~ \.php$ {
    return 404;
}

I use case sensitive matching here (~ modifier instead of ~*). In the first case, I match the first part of path, then one or more number of alphabetic / number characters and then index.php. You can modify the match range, but remember the + for "one or more" repetitions.

The second one matches any URI ending with .php. You don't need the extra characters in your version because of the way regular expressions work.

Solution 2:

Order is important, from nginx's "location" description:

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.

It means:

  • First =. ("longest matching prefix" match)
  • Then implicit ones. ("longest matching prefix" match)
  • Then regex. (first match)

You need to adjust the order of regex parts.