Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nginx proxy or rewrite depending on user agent

i'm new to nginx, comming from apache and i basically want to do the following:

Based on user-agent: iPhone: redirect to iphone.mydomain.com

android: redirect to android.mydomain.com

facebook: reverse proxy to otherdomain.com

all other: redirect to ...

and tried it the following way:

location /tvoice {
   if ($http_user_agent ~ iPhone ) {
    rewrite     ^(.*)   https://m.domain1.com$1 permanent;
   }
   ...
   if ($http_user_agent ~ facebookexternalhit) {
    proxy_pass         http://mydomain.com/api;
   }

   rewrite     /tvoice/(.*)   http://mydomain.com/#!tvoice/$1 permanent;
}

But now i get an error when starting nginx:

nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except"

And i dont get how to do it or what the problem is.

Thanks

like image 696
user984200 Avatar asked May 16 '12 22:05

user984200


2 Answers

The '/api' part of the proxy_pass target is the URI part the error message is referring to. Since ifs are pseudo-locations, and proxy_pass with a uri part replaces the matched location with the given uri, it's not allowed in an if. If you just invert that if's logic, you can get this to work:

location /tvoice {
  if ($http_user_agent ~ iPhone ) {
    # return 301 is preferable to a rewrite when you're not actually rewriting anything
    return 301 https://m.domain1.com$request_uri;

    # if you're on an older version of nginx that doesn't support the above syntax,
    # this rewrite is preferred over your original one:
    # rewrite ^ https://m.domain.com$request_uri? permanent;
  }

  ...

  if ($http_user_agent !~ facebookexternalhit) {
    rewrite ^/tvoice/(.*) http://mydomain.com/#!tvoice/$1 permanent;
  }

  proxy_pass         http://mydomain.com/api;
}
like image 71
kolbyjack Avatar answered Oct 23 '22 18:10

kolbyjack


This is not the best approach because if is devil

The following is the correct approach.

On http{} create a map:

map $http_user_agent $proxied_server {
    # anything not matching goes here 
    default default_domain;

    # case sensitive matching
    ~ (UserAgent) another_domain;

    # case INsensitive matching
    ~* (useragent) third_domain;

    # multiple user agents
    ~* (user|agent|here) forth_domain;
}

Then, in your server{} block:

proxy_pass http://$proxied_server
like image 1
CrazyRabbit Avatar answered Oct 23 '22 20:10

CrazyRabbit