13

I need to write a rewrite rule for Nginx so that if a user tries to go to an old image url:

/images/path/to/image.png

and the file doesnt exist, try to redirect to:

/website_images/path/to/image.png

ONLY if the image exists in the new URL, otherwise continue with the 404. The version of Nginx on our host doesn't have try_files yet.

19
location /images/ {
    if (-f $request_filename) {
        break;
    }

    rewrite ^/images/(.*) /new_images/$1 permanent;
}

Though, you might want to bug your host to upgrade or find a better host.

  • This will redirect to /new_images on every 404 right? I don't want to do the rewrite unless I know the new_images file exists – Jose Fernandez Mar 16 '10 at 13:58
  • This checks to see if the file exists, and if that test fails, it redirects to new_images. What happens after that is not specified here. – tylerl Jul 31 '10 at 7:58
  • I'm afraid that your option is considered as common pitfalls by nginx authors nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/… – riverfall Jan 22 '18 at 10:40
  • 2
    @riverfall Heh, I wrote part of that page. My answer was written 8 years ago so yes it's a wee bit outdated, but the original question did specifically state that their host didn't provide a recent version of nginx so they didn't have access to try_files. – Martin Fjordvald Jan 24 '18 at 8:29
  • 1
    @Guillaume86 I wouldn't worry about that, an if + rewrite is totally safe and a single STAT check on a file is very light weight. It's much faster than going to a backend application to check for maintenance mode. – Martin Fjordvald Aug 30 at 18:37
5

You could use something like this (untested for your specific case):

location ^/images/(?<imgpath>.*)$ {

    set $no_old  0;
    set $yes_new 0;

    if (!-f $request_filename)
    {
        set $no_old 1;
    }

    if (-f ~* "^/new_path/$imgpath")
    {
        set $yes_new 1$no_old;
    }

    # replacement exists in the new path
    if ($yes_new = 11)
    {
        rewrite ^/images/(.*)$ /new_path/$1 permanent;
    }

    # no image in the new path!
    if ($yes_new = 01)
    {
        return 404;
    }
}

Which is basically an alternative way of writing nested if statements, since you cannot nest in Nginx. See here for official reference on this "hack".

5

Please don't use if inside a location block. Bad things may happen.

location ~* ^/images/(.+)$ {
    root /www;
    try_files /path/to/$1 /website_images/path_to/$1 /any/dir/$1 @your404;
}

$1 becomes the filename to try in the try_files directive, which is made for what you're trying to accomplish.

This, OR, just rewrite it without checking. If that image isn't there, you'll get a 404 anyway.

  • While this answer strictly does not answer the question ("[no] try_files yet"), for future visitors coming here, this answer deserves more up-votes. – DerMike Apr 18 at 8:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.