Nginx TCP stream routing based on source IP

nginxroutingtcp

I have configured nginx as a reverse proxy for a TCP (non-http) stream.
I'd like to apply different routing for a particular source IP address – can this be done, and how? I'm aware of recomendations for the http module using the if directive, but that doesn't seem to work for these streams.

Existing configuration:

stream {
  server {
    listen 8000;
    proxy_pass staging;
  }
}

upstream staging {
    server 1.2.3.4:8000;
}

Desired configuration (not working):

stream {
  server {
    listen 8000;
    proxy_pass staging1;
    if ( $remote_addr ~* 4.5.6.7 ) {
        proxy_pass staging2;
    }
  }
}

upstream staging1 {
    server 1.2.3.4:8000;
}
upstream staging2 {
    server 1.2.3.44:8000;
}

This gives error '24314#24314: "if" directive is not allowed here', since it doesn't apply for the stream module – is there any other functionality how I could achieve a similar result?

Best Answer

You can use a directive map for this behavior. Something like this (untested).

upstream staging1 {
    server 1.2.3.4:8000;
}
upstream staging2 {
    server 1.2.3.44:8000;
}

map $remote_addr $upstream {
    4.5.6.7     staging2;
    default     staging1;
}

stream {
    server {
        listen 8000;
        proxy_pass $upstream;
    }
}