I'm trying to configure nginx to perform geoIP checks on first-time visitors only.

The idea is that first-time visitors should be redirected to the page version which has been customised for their language/country.

I'm able to check whether or not a certain cookie exists. If it does, then nginx can proceed and not redirect.

This set up means that all first-time visitors will be redirected to what it's likely to be the most appropriate version of the page for their country/language. And at the same time, those users that wish to, can still browse freely all versions available afterwards.

I believe Google recommends this type of set up for multilingual/multisite webpages too.

The problem is that I get a redirect loop if the rewrite directive is placed outside the root location. Yet, because the US version is the same as /root, rewrites within locations have proven even more difficult to configure.

The geo_IP values are passed OK via fastcgi to php if no rewrite is specified, so I don't think there is anything wrong with the setup apart from the rewrite itself.

This is my config:

map $geoip2_data_country_code $country_url {
  default example.com; ##This is the US version
  GB      example.com/uk;
  CA      example.com/ca;
}

server {
    listen 443 ssl spdy default_server;
    server_name example.com;
    root /var/www/html;

    if ($http_cookie !~ "cookie_to_check") {        
       rewrite ^ https://$country_url break;
       #Appending $request_uri to the rewrite yields very similar results
    }    


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

    location /uk {
    try_files $uri $uri/ /uk/index.php?$args;   
    }

    location /ca {  
    try_files $uri $uri/ /ca/index.php?$args;   
     }

##Other locations
}
  • Use separate hostnames, not directories. – Michael Hampton Jul 30 '15 at 18:12
  • 1
    I don't see where you set cookie – Alexey Ten Jul 30 '15 at 19:55
  • @MichaelHampton That was good to try but nginx doesn't seem to accept subfolders for a server_name. Nginx moans that there are suspicious characters (the forward slash), and although the server starts, the redirect has the same behaviour. I guess this makes sense as a subdirectory would be a location, not a server on its own – cortopy Jul 31 '15 at 11:06
  • @AlexeyTen the cookie is set in the backend with the php application (magento) but thanks for pointing this out. As it turns out, nginx would get confused with the backend cookie. I'll post a full solution with nginx setting a cookie – cortopy Jul 31 '15 at 11:10
  • With this nginx config your backend never get a change to set up cookie. – Alexey Ten Jul 31 '15 at 11:19

After a lot of trial and error, this is the configuration that would work and perform as expected.

The problem with my previous version was double:

  • Nginx rewrites outside locations were messy and they would just refuse to work by creating nasty loops
  • Nginx was checking the existence of a cookie which is set by a php application behind nginx. Thanks to @AlexeyTen for pointing this out. Setting an extra cookie conditionally with nginx did the trick

    map $geoip2_data_country_code $country_url {
         default example.com; ##This is the US version
         GB      example.com/uk;
         CA      example.com/ca;
    }
    
    server {
        listen 443 ssl spdy default_server;
        server_name example.com;
        root /var/www/html;
    
        location / {
            try_files $uri $uri/ /index.php?$args; 
            if ($http_cookie !~ "country=set") {                            
                add_header Set-Cookie "country=set;Max-Age=31536000";
                rewrite ^ $scheme://$country_url$request_uri break;
                }
        }
    
        location /uk {
            try_files $uri $uri/ /uk/index.php?$args;  
            if ($http_cookie !~ "country=set") {                            
                add_header Set-Cookie "country=set;Max-Age=31536000";
                rewrite ^ $scheme://$country_url$request_uri break;
                } 
        }
    
        location /ca {  
            try_files $uri $uri/ /ca/index.php?$args;   
            if ($http_cookie !~ "country=set") {                            
                add_header Set-Cookie "country=set;Max-Age=31536000";
                rewrite ^ $scheme://$country_url$request_uri break;
                }
        }
    
        ##Other locations
        }
    

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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