Search code examples
nginxconfigurationopenresty

Add server locations based on feature flag in an OpenResty nginx.conf file


In an openresty nginx.conf I would like be able to add locations conditionally based on a feature flag value, like as it follows

env ENABLE_UPSTREAMS;
env UPSTREAM_HOST;


http {  
    upstream upstream1 {
        server ${UPSTREAM_HOST1};
    }

    upstream upstream2 {
        server ${UPSTREAM_HOST2};
    }

    map $ENABLE_UPSTREAMS $enable_upstreams {
        "on" 1;
        default 0;
    }

    server {
        listen 80 default_server;
        listen [::]:80 default_server;

        if ($enable_upstreams = 1) {
            location /some-path {
                proxy_pass http://upstream1;
            }

            location /some-path-2 {
                proxy_pass http://upstream2;
            }

        }
    } 
}

but this does not work. I get as error "location" directive is not allowed here in /usr/local/.

I tried to include as a separate *.conf file but still the same error.

than I tried

location /some-path {
     if ($enable_aws_upstreams = 1) {
         proxy_set_header Host $UPSTREAM_HOST;
         proxy_set_header X-Forwarded-For $remote_addr;
         proxy_pass http://upstream2;
     }
} 

but this end in another error "proxy_set_header" directive is not allowed here in and on other side I do not want to expose any path if is disabled by feature flag

What is the right way in this case?


Solution

  • Only handful of directives are allowed inside if block (mosty ngx_http_rewrite_module directives since if itself is a part of this module); neither location nor proxy_* is allowed, hence the error.

    Assuming (from the tag) that you use OpenResty, we can use the power of ngx_http_lua_module.

    Here is a rough example:

    env ENABLE_UPSTREAMS;
    
    http {
        upstream disabled {
            server 127.0.0.1:8001;
        }
    
        upstream upstream1 {
            # upstream1 mock address for demo purposes
            server 127.0.0.1:9001;
        }
    
        upstream upstream2 {
            # upstream2 mock address for demo purposes
            server 127.0.0.1:9002;
        }
    
        server {
            listen 8000;
    
            location /path-1 {
                # we have to predefine the variable
                set $upstream '';
                # set the actual value depending of the environment variable value 
                set_by_lua_block $upstream {
                    if os.getenv('ENABLE_UPSTREAMS') == 'on' then
                        return 'upstream1'
                    else
                        return 'disabled'
                    end
                }
                proxy_pass http://$upstream;
            }
    
            location /path-2 {
                set $upstream '';
                set_by_lua_block $upstream {
                    if os.getenv('ENABLE_UPSTREAMS') == 'on' then
                        return 'upstream2'
                    else
                        return 'disabled'
                    end
                }
                proxy_pass http://$upstream;
            }
        }
    
        # dummy "disabled" upstream, just returns 404
        server {
            listen 127.0.0.1:8001;
            return 404;
        }
    
        # upstream1 mock for demo purposes
        server {
            listen 127.0.0.1:9001;
            return 200 'response from upstream1';
        }
    
        # upstream2 mock for demo purposes
        server {
            listen 127.0.0.1:9002;
            return 200 'response from upstream2';
        }
    }
    

    Without the env variable:

    $ openresty -p . -c nginx_if.conf
    
    $ curl http://localhost:8000/path-1/
    <html>
    <head><title>404 Not Found</title></head>
    <body>
    <center><h1>404 Not Found</h1></center>
    <hr><center>openresty</center>
    </body>
    </html>
    
    $ curl http://localhost:8000/path-2/
    <html>
    <head><title>404 Not Found</title></head>
    <body>
    <center><h1>404 Not Found</h1></center>
    <hr><center>openresty</center>
    </body>
    </html>
    

    With the env variable:

    $ env ENABLE_UPSTREAMS=on openresty -p . -c nginx_if.conf
    
    $ curl http://localhost:8000/path-1/
    response from upstream1
    
    $ curl http://localhost:8000/path-2/
    response from upstream2