2

I am hoping someone can help me with the following. I am trying to setup a reverse proxy for load balancing using nginx over tcp/udp.

I want to be able to redirect some traffic based the client ip address that is connecting up to the proxy server. For this I am using the built-in nginx variable $remote_addr.

The version of nginx I am using is: nginx/1.10.3 (Ubuntu).

The error message I am getting is: nginx: [emerg] "if" directive is not allowed here

This is my config file looks like this:

user www-data;
worker_processes auto;
pid /run/nginx/pid

events {
    worker_connections 768;
}

stream {
    upstream prod_backend {
        server 192.168.137.129:23;
    }
    upstream test_backend {
        server 192.168.137.131:23;
    }

    server {
        listen 23;

        if ( $remote_addr = 192.168.137.132 ) {
            proxy_pass test_backend;
        }

        proxy_pass prod_backend;
    }
}

http {
}

After seeing this answer here, I have tried using the Geo module but get the same problem.

user www-data;
worker_processes auto;
pid /run/nginx/pid

events {
    worker_connections 768;
}

stream {
    upstream prod_backend {
        server 192.168.137.129:23;
    }
    upstream test_backend {
        server 192.168.137.131:23;
    }

    geo $test_site {
        default 0;
        192.168.137.132 1;
    }

    server {
        listen 23;

        if ( $test_site ) {
            proxy_pass test_backend;
        }

        proxy_pass prod_backend;
    }
}

http {
}

when I run the above version I get the error:

nginx: [emerg] "geo" directive is not allowed here

I am obviously doing something wrong but don't know what!

Ocean Airdrop
  • 151
  • 1
  • 8
  • Because you can use "if" only within server and location context. And your stream section use main context. The same thing with geo. – ALex_hha Dec 07 '17 at 10:08
  • But if you look at my 1st example, the "if" statement is within the server context. Can you provide an example please? – Ocean Airdrop Dec 07 '17 at 10:55
  • It's because your server section inside stream which in main context, imho – ALex_hha Dec 07 '17 at 12:36
  • But you cant put the server section outside the stream. – Ocean Airdrop Dec 07 '17 at 13:07
  • What do you mean? It's because server block can be placed only in http context - http://nginx.org/en/docs/http/ngx_http_core_module.html#server – ALex_hha Dec 07 '17 at 13:20
  • Hmm. That's not correct as per the documentation I have been following here. see here: https://www.nginx.com/resources/admin-guide/tcp-load-balancing/. – Ocean Airdrop Dec 07 '17 at 13:23
  • This config is not for http traffic. Are you saying I can use the http context and this will still work? I can try that. – Ocean Airdrop Dec 07 '17 at 13:26
  • http://nginx.org/en/docs/http/ngx_http_rewrite_module.html because "if" it's a directive of http_rewrite module, you can't use it inside stream module. You can use it only within ```http{ server { ... } }``` – ALex_hha Dec 07 '17 at 15:04
  • I see. Thanks ALex_hha. So I need to look for an alternative method of filtering ip traffic with: stream { server { ... } } – Ocean Airdrop Dec 07 '17 at 15:14
  • found the alternative method by using the map function which is supported in the stream context. – Ocean Airdrop Dec 09 '17 at 10:01

1 Answers1

3

As user @Alex_hha pointed out, the "if" directive can only be used within the http directive.

After some research around this area I have now found a solution to the problem.

If you are using the stream directive for generic TCP/UDP traffic an alternative to the if statement is to use the map function.

Using this method my config file now looks like this:

stream {
   upstream prod_backend {
      server 192.168.137.129:23;
   }

   upstream test_backend {
      server 192.168.137.131:23;
   }

   map $remote_addr $backend_svr {
      192.168.137.140:23 "test_backend";
      default "prod_backend";
   }

   server {
      listen 23;
      proxy pass $backend_svr;
   }
}

In this example, if a client connects with the IP address of 192.168.137.140 it will get sent to the test_backend upstream block.

The version of nginx I am using is: nginx/1.12.1 (Ubuntu).

Ocean Airdrop
  • 151
  • 1
  • 8