Nginx rewrite URL only if file exists
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.
Solution 1:
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.
Solution 2:
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.
Solution 3:
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".