Nginx redirect based on user agent

Solution 1:

There are Two ways to fix this issue.

  1. Have two seperate "server" blocks for www.domain.com & www.domain2.com and add the following lines of rules to "server" block www.domain.com. This is recommended way to solve this issue.

    if ($http_user_agent ~* "^xxx$") {
       rewrite ^/(.*)$ http://www.domain2.com/$1 permanent;
    }
    
  2. If you want to manage the redirect with a single "server" block for both domains, Try below rules

    set $check 0;
    if ($http_user_agent ~* "^xxx$") {
        set $check 1;
    }
    if ($host ~* ^www.domain.com$) {
        set $check "${check}1";
    }
    if ($check = 11) {
        rewrite ^/(.*)$ http://www.domain2.com/$1 permanent;
    }
    

Solution 2:

Step 1: Have two server blocks, one each for domain.com and domain2.com.

Step 2: Use if correctly as it is evil if used incorrectly.

Here's the complete solution...

server {
  listen 90;
  server_name www.domain.com;
  root /root/app;

  # redirect if 'xxx' is found on the user-agent string
  if ( $http_user_agent ~ 'xxx' ) {
    return 301 http://www.domain2.com$request_uri;
  }

  location / {
    try_files $uri =404;
  }
  location ~ /([-\w]+)/(\w+)/ {
    proxy_pass bla bla
  }
}

server {
  listen 90;
  server_name www.domain2.com;
  root /root/app;
  location / {
    try_files $uri =404;
  }
  location ~ /([-\w]+)/(\w+)/ {
    proxy_pass bla bla
  }
}

Solution 3:

The recommended way would probably be using a map, also because these variables are evaluated only when they are used.

Also the use of return 301 ... is preferred over rewrites, because no regular expression have to be compiled.

Here an example of where host and user-agent as a concatenated string are compared to a single regex:

map "$host:$http_user_agent" $my_domain_map_host {
  default                      0;
  "~*^www.domain.com:Agent.*$" 1;
}

server {
  if ($my_domain_map_host) {
    return 302 http://www.domain2.com$request_uri;
  }
}

And this could be even more flexible, for example if a there not 2 but more domains involved.

Here we map www.domain.com with user-agents starting with Agent to http://www.domain2.com and www.domain2.com with the exact user-agent Other Agent to http://www.domain3.com:

map "$host:$http_user_agent" $my_domain_map_host {
  default                             0;
  "~*^www.domain.com:Agent.*$"        http://www.domain2.com;
  "~*^www.domain2.com:Other Agent$"   http://www.domain3.com;
}

server {
  if ($my_domain_map_host) {
    return 302 $my_domain_map_host$request_uri;
  }
}

NB you will need nginx 0.9.0 or higher for the concatenated string in map to work.