Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I'm attempting a website cut-over. We want to preserve our external links by using 301 redirects. I have a lengthy list of redirects in a named location that resembles:

location @redirects {       
    rewrite ^/path/one.html$ http://www.ourdomain.tld/one-but-different permanent;
    rewrite ^/path/two.html$ http://www.ourdomain.tld/two-but-different permanent;
    rewrite ^/path/three.html$ http://www.ourdomain.tld/three-but-different permanent;
    rewrite ^/path/four.html$ http://www.ourdomain.tld/four-but-different permanent;
}

(please note that even though it appears that my example shows a pattern, no pattern exists. In other words they are one-to-one redirects.)

I have a CMS web application that I'm using the following try_files statement currently (which has been working all along for falling back to the index.php script):

location / {
    try_files $uri $uri/ /index.php;
}

Now I'm attempting to use try_files to "look at" the redirects named location and processing the rewrite BEFORE falling back to index.php. Like this:

location / {
    try_files @redirects $uri $uri/ /index.php;
}

However, the fallback is being triggered each time as the CMS is handling 404's. In other words, if I try http://www.ourdomain.tld/path/one.html, I get the 404 page for my CMS instead of a redirect! Is it possible to "try" a named location first or does the named location have to be the fallback?

I'm sure I'm doing this wrong. However, can someone point me in the right direction?

nginx/1.2.4

Thanks!

share|improve this question
    
I suppose I can just throw my redirects into the server directive but I'd prefer to keep them in a named location if possible. Thanks! –  Bretticus Nov 20 '12 at 0:08
1  
Did you read the documentation: nginx.org/r/try_files ? try_files does not try locations, it tries files. –  VBart Nov 20 '12 at 0:10
    
I guess that answers my question. Thanks @VBart. That makes impeccable sense. I suppose I need to stick it in the server block after all. –  Bretticus Nov 20 '12 at 0:19
add comment

2 Answers 2

up vote 1 down vote accepted

The right way is:

location = /path/one.html {
    return 301 http://www.ourdomain.tld/one-but-different;
}

location = /path/two.html {
    return 301 http://www.ourdomain.tld/two-but-different;
}

etc...

Please, avoid to use rewrites if possible. Nginx isn't Apache. URL rewriting is an inefficient and tricky way of configuring web server. Nginx prefers URL-mapping. The location prefix matching is very fast and efficient.

http://wiki.nginx.org/Pitfalls

--

In the case of a very large number (500+) of redirects:

map $uri $redirect_to {
    include /path/to/redirects.map;
}

server {
    location / {
        if ($redirect_to) {
             return 301 http://www.ourdomain.tld$redirect_to;
        }
    }
}

redirects.map:

/path/one.html /one-but-different;
/path/two.html /two-but-different;
etc...
share|improve this answer
    
Thanks, I had seen this answer before and tried to avoid it because I have about 1000 of these redirects. I own several good text editors and I'm proficient with regular expressions, however, I just wanted to avoid all the extra characters. And I come from a long-time Apache background! LOL. Thanks again! –  Bretticus Nov 20 '12 at 0:21
1  
If you have ~1000 redirects, then probably the map directive will be more efficient. Note, it has the include parameter that can be very useful in your case. nginx.org/r/map –  VBart Nov 20 '12 at 0:26
    
Thanks again @VBart! –  Bretticus Nov 20 '12 at 0:27
1  
You're welcome. –  Michael Hampton Nov 20 '12 at 0:39
add comment

Another way you can do this is with a map.

An example; off the top of my head so check for syntax errors first...:

map $uri $new {
  /path/one.html http://www.example.com/new_path_one;
  /path/two.html http://www.example.com/new_path_two;
}

server {
  if ($new) {
    return 301 $new;
  }
  ....
}
share|improve this answer
    
I saw vbart's response first. Must have just missed your answer here. Thanks. I was actually just looking for how to implement. Would you humor me by explaining what $new is? $uri is the current request URI. But $new is undocumented. Just wondering how nginx determines that it should substitute $new for the $uri when $new is true??? –  Bretticus Nov 20 '12 at 2:35
    
$uri is set by nginx to the request URI. $new is any variable name you want. $new is set to the corresponding value when $uri matches one of the patterns given (you can also use regexes here). –  Michael Hampton Nov 20 '12 at 2:51
    
Okay, so how on earth does if ($new){... work? Does the hash map work both directions? –  Bretticus Nov 20 '12 at 2:52
1  
If $new was set to a value by the map, then the return statement gets executed. If the map didn't match anything, then $new will not be set, and the return will not happen. –  Michael Hampton Nov 20 '12 at 2:54
    
Thanks Michael, that finally makes sense! –  Bretticus Nov 20 '12 at 2:57
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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