2

I want a request to http://example.com/foobar to return http://example.com/foobar.jpg. (Or .gif, .html, .whatever)

This is trivial to do with Apache MultiViews, and it seems like it would be equally easy in Nginx. This question seems to imply that it'd be easy as try_files $uri $uri/ index.php; in the location block, but that doesn't work.

try_files $uri $uri/ =404; doesn't work, nor does try_files $uri =404; or try_files $uri.* =404; Moving it between my location / { block and the regexp which matches images has no effect.

Crucially, try_files $uri.jpg =404; does work, but only for .jpg files, and it throws a configuration error if I use more than one try_files rule in a location block!

The current server { block:

server {
        listen   80;
        server_name     example.org www.example.org;
        access_log  /var/log/nginx/vhosts.access.log;
        root   /srv/www/vhosts/example;
        location / {
                root   /srv/www/vhosts/example;
        }

        location ~* \.(?:ico|css|js|gif|jpe?g|es|png)$ {
                expires max;
                add_header Cache-Control public;
                try_files $uri =404;
        }
}

Nginx version is 1.1.14.

1
  • You should be able to simply list the files to try in order: try_files $uri.jpg $uri.gif $uri.png $uri.css $uri.js $uri/ =404.
    – cyberx86
    Apr 7, 2012 at 1:35

1 Answer 1

5

You can emulate Apache's MultiViews, by passing the various filenames to try to try_files.

Nginx's try_files directive does exactly what the name suggests - it tries files in the order the are specified, and if not found, will move to the next file. Typically, the last entry is a fallback that is guaranteed to work - either a named location block, or an error page.

The commonly seen parameters of try_files: $uri and $uri/ really are the paths passed to nginx - with and without the trailing slash.

So, if you go to example.com/path/to/myfile

$uri = /path/to/myfile
$uri/ = /path/to/myfile/

With the try_files $uri $uri/ directive, nginx will try exactly what is passed ($uri) - and if that file exists, will serve it, otherwise will try to find a matching directory ($uri/) and serve that (using whatever index you have specified).

Since the files you are trying to serve don't actually match the path in $uri, you need to append the extension to $uri for it to work:

$uri.jpg will match (from the above example) myfile.jpg - hence why only JPEGs worked when you used it.

Since you can specify multiple files to try in try_files, having more than one try_files directive doesn't really make sense - which is why it is not allowed.

In its simplest form, therefore, just list the files you want, in the order you wish to try them (e.g.):

try_files $uri.jpg $uri.gif $uri.png $uri.css $uri.js $uri/ =404

The second location block is interesting in this case. Typically, nginx will only ever process one location block - the one that matches best. However, in the case of rewrite ... last processing will restart and check all available location blocks. This is essentially what try_files amounts to - check if exists and rewrite ... last, the key difference being the absence of the arguments passed which are stripped by try_files unless explicitly added (e.g. with $uri?$args).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .