I have the following in my nginx config file, it works, but I don\'t want to have to list every file extension.
location ~ \\.(gif|jpg|png|css|js|ttf|woff|ht
Nginx uses the PCRE library written in C. There's a huge man page, a bit hard to understand sometimes but quite detailed. Among it, you will find the look ahead / look behind functionnalities as you would find them in Perl.
Positive/negative look ahead/behind allow to match a string if one part of it is/isn't followed/preceded by an expression. Look behind expressions are restricted to a fixed string because it's not possible for most implementations to apply a regular expression backwards as you need to know how many steps you go back for this. Look ahead doesn't obviously suffer from this limitations, so you can use a regular expression like you usually do.
Here's the relevant section of the man page :
LOOKAHEAD AND LOOKBEHIND ASSERTIONS
(?=...) positive look ahead (?!...) negative look ahead (?<=...) positive look behind (?<!...) negative look behind Each top-level branch of a look behind must be of a fixed length.
Unfortunately you can't capture the end of the string with look ahead.
So, our first attempt will be using negative look behind from the end of the string :
location ~ .+(?<!\.php)$ {
...
}
Which means "Only capture strings that don't end with .php
". That's quite close from what we need already. But there's something more to add to make it work like expected.
Indeed, nothing guarantees that you will have a string containing a file extension at this point. It could rather be anything except ^.+\.php$
. To make sure this is a real file suffix, the natural way to overhaul this limit is by using nested location blocks where the most restrictive part is the apex. So our configuration will now look like below.
location ~ .+(?<!\.php)$ {
location ~ ^[^.]+\.[^.]+$ {
try_files $uri /images/default.gif;
}
}
And that's it !
Here are my remarks after your post update for the second issue you are facing (404 errors on other URLs).
As ~ .+(?<!\.php)$
matches everything except \.php$
and locations are nested, you need to nest the location block /
and transform it to a regex match :
location ~ .+(?<!\.php)$ {
location ~ ^[^.]+\.[^.]+$ {
try_files $uri /images/default.gif;
}
location ~ / {
# your stuff
}
}
Also note that you can end up with an infinite loop with the try_files $uri /images/default.gif;
part because the last paremeter of the try_files
directive is an internal redirect or an HTTP code. So if /images/default.gif
doesn't resolve to a file, the request will go trough this location block 10 more times until nginx stops the processing and return HTTP 500. So change it to try_files $uri /images/default.gif =404;
.