3

I'm trying to use the map of nginx, but the results aren't what I expect.

This is what I have:

map $uri $new {
  default                                 "";
  ~*/cc/(?P<suffix>.*)$                   test.php?suffix=$suffix;
}

location ~     [a-zA-Z0-9/_]+$ {
        proxy_pass http://www.domain.com:81/$new;
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

When I go to www.domain.com/cc/abc, I see this in the logs

2012/03/29 17:27:53 [warn] 3382#0: *33 an upstream response is buffered to a temporary file /var/cache/nginx/proxy_temp/5/00/0000000005 while reading upstream, client: 1.2.3.4, server: www.domain.com, request: "GET /cc/abc HTTP/1.1", upstream: "http://1270.0.0.1:81/test.php?suffix=$suffix", host: "www.domain.com"

The $suffix isn't replaced.

But when I do this:

map $uri $new {
  default                                 "";
  ~*/cc/(?P<suffix>.*)$                   $suffix;
}

location ~     [a-zA-Z0-9/_]+$ {
        proxy_pass http://www.domain.com:81/$new;
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

And now, when I go to go to www.domain.com/cc/abc, the logs show me this:

2012/03/29 17:29:39 [warn] 5916#0: *26 an upstream response is buffered to a temporary file /var/cache/nginx/proxy_temp/2/00/0000000002 while reading upstream, client: 1.2.3.4, server: www.domain.com, request: "GET /cc/abc HTTP/1.1", upstream: "http://1270.0.01:81/abc", host: "www.domain.com"

So, when the rewrite contains a string including the variable, it isn't replaced. But if it only contains the variable, it will work.

What am I doing wrong?

1 Answer 1

9

As you've discovered, map replacements can only be a static string or a single variable. Since test.php?suffix=$suffix doesn't start with a $, nginx assumes it's just a static string. Instead of using a map, you'll need to use two rewrites to accomplish what you want:

location ~ [a-zA-Z0-9/_]+$ {
  rewrite ^/cc/(.*) /test.php?suffix=$1 break;
  rewrite ^ / break;

  proxy_pass http://www.domain.com:81;
  proxy_set_header X-Real-IP  $remote_addr;
  proxy_set_header Host $host;
  proxy_set_header X-Host $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

The first rewrite will strip any initial /cc/ from the url and append the rest as the url arg like your map was trying to. The break flag tells nginx to stop processing rewrite directives. If the first rewrite doesn't match, then the second will always match, and will set the url to /.

EDIT: As of 1.11.0, map values can be complex values, so the original config would work

Sign up to request clarification or add additional context in comments.

4 Comments

Hmm, that's pity :( Thought I could use map, because they are much faster then rewrite. I'm going to play with the rewrites tomorrow, will let you know if it works. Tnx in advance!
Btw, why does the documentation gives an example that it's possible? wiki.nginx.org/HttpMapModule That's why I tried it in the first place. Or is it only possible, if you use the map to use the value as rewrite in your server section?
Can you remove the example below as well? In the Directives chapter
That example is correct. You can use a single variable as the replacement.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.