15

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.

3 Answers 3

20
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.

6
  • 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 Mar 16, 2010 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, 2010 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, 2018 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. Jan 24, 2018 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. Aug 30, 2019 at 18:37
9

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. Honestly if you don't have try_files, the solution should probably be upgrading nginx to the latest stable branch.

1
  • 1
    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, 2019 at 8:51
6

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".

You must log in to answer this question.

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