8

I need to route traffic based on the http request origin. I have two environments and we need to redirect every http request for "/us-en" to Environment1 and others to Environment2 using "$http_referer".

  1. Redirection based on location works.
location ~ /us-en { 
    proxy_pass Environment1; 
    proxy_set_header Host Environment1; 
} 
  1. With '$http_referer' the below option does not work. Request your suggestion on the same.
if ($http_referer ~ ^https?://dev.xyz.com/us-en){ 
    rewrite ^/us-en(/*)$ HOME_PAGE$1 break; 
    proxy_pass Environment1; 
}
Error: nginx: [emerg] "proxy_pass" directive is not allowed here in /opt/nginx/conf/nginx.conf.

Note: By default all the traffic goes to Environment2 as an upstream configuration is present.

Debarshi DasGupta
  • 351
  • 2
  • 5
  • 21
  • 1
    Are you sure you want to check exactly an `Origin` header, not a `Referer`? `Origin` header does not includes an URI (in your case, it can be `http://dev.xyz.com` or `https://dev.xyz.com`) and is issued by browser mostly on AJAX requests. – Ivan Shatsky Dec 11 '18 at 08:24
  • Yeah, referer is more appropriate. Can you suggest on the syntax? – Debarshi DasGupta Dec 11 '18 at 08:39

1 Answers1

14
    # needed if your proxy destination specified with domain name instead of IP address
    resolver 8.8.8.8;

    location /home/ {
        proxy_set_header Host HOST1;
        # setup other proxied headers if needed
        if ($http_referer ~ ^https?://dev.xyz.com/home) {
            rewrite ^/home(/.*)$ HOME_PAGE$1 break;
            proxy_pass https://HOST1:8080; # this can be specified by IP address
        }
    }

With such configuration requests to your_domain.com/home/path/file from dev.xyz.com/home/... (but not from dev.xyz.com/any/other/path!) will be proxied to https://HOST1:8080/HOME_PAGE/path/file. If you specify your proxy destination with domain name instead of IP address, you'll need to specify the additional parameter resolver in your server config. You can use your local name server if you have one, or use something external like Google public DNS (8.8.8.8) or DNS provided for you by your ISP. Anyway such configuration leads to additional DNS lookups, so if you can, specify your proxy destination with IP address.

Update

There is another way to do it with the valid_referers directive:

    # needed if your proxy destination specified with domain name instead of IP address
    resolver 8.8.8.8;

    location /home/ {
        proxy_set_header Host HOST1;
        # setup other proxied headers if needed
        valid_referers example.com/home;
        if ($invalid_referer = "") {
            rewrite ^/home(/.*)$ HOME_PAGE$1 break;
            proxy_pass https://HOST1:8080; # this can be specified by IP address
        }
    }

Update @ 2020.11.11

Besides this answer somehow achieved a score of 5, the given solution has an extremely bad design (it isn't a good approach to have different content handlers in the location and the nested if block; moreover, having an if block with any directive other than from the nginx rewrite module should be avoided if possible) and won't work at all on early nginx versions (I wanna cry when I look at some of my early answers). An original OP question was

The logic should be like below but has some syntax mistakes.

if ($http_origin ~ '^http?://(dev.xyz.com/home)') {
    set $flag 'true';
}

if ($flag = 'true') {
    location /home/ {
        proxy_pass  "https://HOST1:8080/HOME PAGE/";        
    }
}else{
    Do Not proxy pass
}

It is unclear what do not proxy pass means. If it means returning some HTTP error (for example, HTTP 403 Forbidden), it can be done with the following configuration:

location /home/ {
    if ($http_referer !~ ^https?://dev.xyz.com/home) {
        return 403;
    }
    rewrite ^/home(/.*)$ HOME_PAGE$1 break;
    proxy_set_header Host HOST1;
    # setup other proxied headers if needed
    proxy_pass https://HOST1:8080; # this can be specified by IP address
}

If do not proxy pass means to serve the request locally, the solution is more complex:

map $http_referer $loc {
    ~^https?://dev.xyz.com/home    loc_proxy;
    default                        loc_local;
}

server {
    ...
    location /home/ {
        try_files /dev/null @$loc;
    }
    location @loc_proxy {
        rewrite ^/home(/.*)$ HOME_PAGE$1 break;
        proxy_set_header Host HOST1;
        # setup other proxied headers if needed
        proxy_pass https://HOST1:8080;
    }
    location @loc_local {
        rewrite ^/home(/.*)$ HOME_PAGE$1 break;
        root /path/to/required/page;
        ...
    }

The try_files /dev/null @the_named_location; trick is taken from this excellent answer.

However now the edited OP's question states for a different requirements, which also could be achieved with the map directive help:

map $http_referer $environment {
    ~^https?://dev.xyz.com/home    Environment1;
    default                        Environment2;
}

server {
    ...
    location /home/ {
        rewrite ^/home(/.*)$ HOME_PAGE$1 break;
        proxy_set_header Host $environment;
        # setup other proxied headers if needed
        proxy_pass https://$environment;
    }
Ivan Shatsky
  • 13,267
  • 2
  • 21
  • 37
  • 1
    Thanks for your suggestion #1. Redirection based on location works ***** location ~ /HOME_PAGE { proxy_pass http://IP_ADDRESS; proxy_set_header Host IP_ADDRESS; } ***** #2. With '$http_referer' the below option does not work. Request your suggestion on the same. ***** if ($http_referer ~ ^https?://dev.xyz.com/HOME_PAGE){ rewrite ^/HOME_PAGE(/*)$ HOME_PAGE$1 break; proxy_pass https://IP_ADDRESS; } ***** Error: nginx: [emerg] "proxy_pass" directive is not allowed here in /opt/nginx/conf/nginx.conf – Debarshi DasGupta Jan 29 '19 at 12:45
  • @DebarshiDasGupta can you update your question with this info? Stackoverflow has very limited capabilities of comments formatting, and this is really very hard to read. – Ivan Shatsky Jan 29 '19 at 12:56
  • 1
    It seems that this `if` constriction located outside of any `location` block? Try to put it inside the default `location` block. BTW it would be much simple to suggest appropriate solution if you provide your full nginx configuration. – Ivan Shatsky Jan 29 '19 at 13:43